2017-02-16 131 views
0

我想写一个递归阶乘函数来练习我的递归以及与此想出了:如何递归阶乘函数知道何时停止

function test(num){ 
    return (num * test(num - 1)) 
} 

但是,每当我运行它,它永远循环和我得到一个范围错误:超出最大调用堆栈大小。

但如果我把它写来处理异常,

function factorial(num) { 
    if (num < 0) { 
     return -1; 
    } else if (num === 0) { 
     return 1; 
    } else { 
     return (num * factorial(num - 1)); 
    } 
} 

它完美。

2个问题。

  1. 为什么第一个不工作?

  2. 第二个人如何知道何时停止跑步。如果num实际上是改变其由-1每次它最终将命中0,它应该引发否则,如果和返回值1,你要是跑不过因子(3)它返回6.

+0

第一个总是调用自己('test()') - 它没有条件停止。第二个会在'num === 0'时停止。 – bejado

+0

第二个语句有一个'if()'语句,并且在到达基本情况时不会递归。这是递归的本质。 – Barmar

+0

第二个工作,因为即使它返回1,该结果在调用它的函数中乘以num(num = 1),然后是2,依此类推调用堆栈 – samgak

回答

2
  1. 递归必须有一个基本情况 - 满足功能停止的条件。

  2. 您正在下降,从numnum-1,以此类推,直到0,此时的功能满足基本情况:num == 0并返回1.从这点递归解开回来,乘1 * num-(num-1).. 。num

此外,阶乘只用于非负整数返回中定义-1,所以没有多大意义。另一件事:基本案例应该真的是num == 1

你正在做的事情是乘以1num ==1然后再乘以1,当num == 0 它返回错误的阶乘 factorial(0).

编辑:阶乘(0)为1。所以,你确实是正确的返回1,但我仍然把它作为一个角落的情况。不需要等待额外的步骤来达到0.

function factorial(n){ 
    // Handle the corner cases: you might as well just throw an error 
    if (n < 0) return undefined; 
    if (n == 0) return 1; 

    // Base case 
    if (n == 1) return 1; 

    // Iterative step 
    // (If the function got to this point, it means, that n > 1) 
    return n * factorial(n - 1); 

    // In order to return the expression on the right side of "return", 
    // You need to calculate the `factorial(n - 1)` 
    // When you try calculating it, you will see, that now you need to 
    //  find out the `factorial(n - 1)` again, but this time the 
    //  `n` is actually `(n - 1)` :) 
    // So this way, you are digging into the call stack. 
    // At some point you reach the 1. WHICH RETURNS 1. WOOHOO. 
    // No need to calculate the `factorial` anymore. 
    // Now all the expressions you couldn't evaluate, get evaluated 1 by 1 
} 
+0

递归过程的良好描述。谢谢。我的头仍然很难缠绕,但这是我见过的最好的解释。现在有点合理。哈哈。我只是需要更多地使用它们,直到它们开始有意义 – nwimmer123

+0

@ nwimmer123我已经更新了一些说明,希望它更清楚。 – hlfrmn