堆栈中将存储多少个调用?

时间:2015-02-25 05:04:12

标签: java recursion stack fibonacci

有人可以解释下面的递归方法将在堆栈中存储多少个调用,为什么?什么东西准确存储在堆栈中?显然这是49个电话,但我不明白为什么。谢谢。

public static long fib( int n ){ // n = 50
    if( n <= 1 )
        return 1;
    else
        return fib( n - 1 ) + fib( n - 2 );
    }

3 个答案:

答案 0 :(得分:6)

下面的递归方法将在堆栈中存储多少个调用以及为什么?

输入为50时,任何给定时刻的最大堆栈帧数(包括对fib的初始调用)将为50.(因此堆栈上最多存储49个递归调用)任何特定的时刻)。

最多可以有50个堆栈帧的原因是:

fib(50)的初始调用是1个堆栈帧。

然后使用此声明,return fib( n - 1 ) + fib( n - 2 ); 左边的fib的递归调用将首先执行,将fib(49)放在堆栈上。我们将再次点击返回线,将fib(48)放在堆栈上。这将重复,直到fib(1)在堆栈上点击return 1;语句。这将返回fib(2)并允许正确的递归调用在语句return fib( n - 1 ) + fib( n - 2 );中执行。

为了简化长篇故事,所有左递归调用都会在1次正确的递归调用之前执行。所以很容易看到你有fib(50)fib(49),...,最后fib(1)用于最后一次递归调用,导致执行时最多有50个堆栈帧{{ 1}}。

什么东西准确存储在堆栈中?

调用函数时,将分配堆栈帧,并在函数返回后,释放堆栈帧。甚至对fib(50);的函数调用也存储在堆栈中。但是,堆栈帧可能会被优化掉,但这是一个更高级的主题。

看到这个问题,如果你想了解更多有关叠加帧的信息,我会问我什么时候是小伙伴:

Does a stack frame really get pushed onto the stack when a function is called?

其他编辑: 如果您想了解如何通过视觉进行递归,请将手指放在根的顶部,并首先在左侧的树的外侧追踪: enter image description here

答案 1 :(得分:1)

想象一下堆栈帧作为人工,你发送它来获取一些信息。暂时忘掉斐波纳契,想一下更简单的递归公式,即总和。

int sum(int n) {
  if (n == 1) {
    return 1;
  } else {
    return sum(n - 1) + n;
  }
}

sum(1) = 1

sum(2) = sum(1) + 2 = 1 + 2 = 3

等...

现在想象一下,当你打电话给sum(n)时,你会发送一个人来为你找到结果。他没有“完成”工作,直到他给你你要求的结果。但是,他还需要打电话给sum(n - 1),他只能通过让另一个人去工作来做。现在我们有两个人同时工作!你问的问题是同时工作的最大人数是多少?如果你包括你自己,那么对于上面实现的和算法,对于Fibonacci,答案是n实施了它。

答案 2 :(得分:0)

堆栈中对fib的调用次数是需要调用fib来评估fib(n)的次数。

fib(50)将有超过49次调用fib函数。

举一个小例子。如果您致电fib(3),则会拨打fib(2)fib(1)fib(2)会致电fib(0)fib(1)。这已经是fib(3)的5次调用。

对于较大的n值,每次调用fib(3)将导致总共5次调用,因为这些值不会存储在任何位置。 fib评估的唯一方法是将自己称为两个较小的值。

Fibonacci序列是递归使用不良的标准示例,因为成本是指数级的。我会告诉你究竟需要多少次电话。