试图学习递归函数,但无法绕过它

时间:2011-09-13 19:34:02

标签: javascript recursion

我正在尝试学习如何使用递归函数,但我不了解发生了什么。

function power(base, exponent) {
    return base * power(base, exponent - 1);
};

alert(power(4,4));

我得到了:

  

RangeError:超出最大调用堆栈大小。

从我要离开的例子来看,它有:

function power(base, exponent) {
  if (exponent == 0)
    return 1;
  else
    return base * power(base, exponent - 1);
}

alert(power(4,4));

有人可以向我解释为什么需要if语句吗?我怀疑我错过了什么。

7 个答案:

答案 0 :(得分:8)

递归函数调用自身。这就是它的定义。

这带来了一个问题:它将无限期地调用自己。所以它将永远存在,这就是为什么你会得到堆栈溢出。

相反,你应该停在某一点上。这是if子句的来源。当exponent == 0时,您不调用该函数,而是停止该过程。

因此,在执行power(3, 3)时,它会像:

   power(3, 3) is equal to:

   3 * power(3, 2)
or 3 * 3 * power(3, 1)
or 3 * 3 * 3 * power(3, 0)
or 3 * 3 * 3 * 1            // no additional calls anymore; can be calculated now

从一个不同的角度看:

  • power(4, 4)被函数定义为4 * power(4, 3)
  • power(4, 3)被函数定义为4 * power(4, 2)
  • power(4, 2)被函数定义为4 * power(4, 1)
  • power(4, 1)被函数定义为4 * power(4, 0)
  • power(4, 0)被函数定义为1

如果您将所有内容替换为前一个内容,您将获得:

                         power(4, 4)
equals               4 * power(4, 3)
equals           4 * 4 * power(4, 2)
equals       4 * 4 * 4 * power(4, 1)
equals   4 * 4 * 4 * 4 * power(4, 0)
equals   4 * 4 * 4 * 4 *      1   
equals   256

答案 1 :(得分:5)

在递归中需要一个基本案例,以便它停止调用自身。在这种情况下,幂函数被永远调用(好吧,直到javascript解释器放弃),因为指数变为负无穷大。

答案 2 :(得分:3)

递归函数调用自身。因此,您需要一些机制来告诉它停止,否则您将处于无限循环中。在你的情况下,你总是返回并且没有提供退出循环的方法。因此RangeError。

答案 3 :(得分:3)

请注意,该函数正在调用自身。在您的第一个示例中,函数调用自身,然后新调用的函数调用自身,依此类推。在内部,您的计算机将这些函数调用存储在称为堆栈的内存结构中。当没有更多用于存储函数调用的内存时,您已超出调用堆栈大小。

在第二个例子中,你有办法摆脱这种恶性循环。基本情况允许函数返回,因此您将方法调用“弹出”到堆栈中。

请注意,在第二个示例中,您可以从alert(power(4,-1))开始,然后您将再次遇到相同的问题,因为现在您的函数将从-1中减去1,给出-2,并且等等。您可以使用

强化代码
if (exponent <= 0 ) 

......而不是。

答案 4 :(得分:2)

你必须给它一些角落条件,否则它会一遍又一遍地自我调用。由于堆栈大小有限,它将到达堆栈内存的末尾,然后将抛出错误。

答案 5 :(得分:2)

递归实际上是在它自己的函数体内再次调用函数&amp;再次,直到你得到你想要的结果。

public int FactorialOfNumber(int k) {

    if (k==1)
        return 1;
    else
        return k * FactorialOfNumber(k-1);  //Function called within Function.
}

Recursion使用堆栈运行会发生什么?

假设k = 1,则返回1.

如果k = 4,则控制转到else,返回(4 * FactorialOfNumber(3))。因为你不知道,FactorialOfNumber(3)。它存储在堆栈顶部。

现在,k = 3,控制转到else,它返回(3 * FactorialOfNumber(2))。这就是堆栈顶部。

现在k = 2,返回(2 * FactorialOfNumber(1)),堆栈顶部。

最后它调用了来自堆栈的pop,最后调用了(4 * FactorialOfNumber(3))。

如果递归方法永远不会达到基本情况,那么堆栈永远不会停止增长。但是,计算机将堆栈限制在特定高度,因此没有程序会占用太多内存。如果程序的堆栈超过此大小,计算机将启动异常,这通常会使程序崩溃。该异常标记为StackOverflowError。

答案 6 :(得分:1)

当指数达到零时,if创建一个检查以停止递归。没有它,它将继续负值并永不停止。