我觉得这个递归函数感觉像是'for循环'我错了吗?

时间:2013-07-16 13:30:18

标签: javascript loops recursion

有人可以解释这个递归函数如何产生5 * 4 * 3 * 2 * 1来获得120?

var factorial = function(n){
   if (n === 0)
       return 1;
   else
       return n * factorial(n - 1); 
};

factorial(5); // spits out 120

如果我们在示例中使用5之类的,那么一旦我们得到else语句就不会

return n * factorial(n - 1);

转换为'返回5乘以阶乘函数(5-1); 5次......

4 个答案:

答案 0 :(得分:4)

  

我觉得这个递归函数感觉像是'for循环'我错了吗?

不,递归和循环有很多共同之处。特别是,它们都具有终止条件非常重要。 :-)在这种情况下,终止条件是n === 0

理解这一点的最佳方法是在调试器中单步执行代码。您的浏览器有一个,因此您可以将该代码放在页面中并加载它并遍历它。

为了帮助您入门:

  1. 您致电factorial(5)。由于n不是=== 0factorial会将自己称为n - 14

  2. 现在我们已经递归了一个级别,我们正在运行factorial(4)(对factorial(5)的调用仍然没有返回,它正在等待我们)。由于n不是=== 0,我们会调用factorial(3)并等待 it 返回。

  3. ...冲洗,重复直至factorial(0)被召唤。由于n === 0为真(此时有五次调用factorial未完成且已堆叠),factorial(0)会返回1,我们可以开始展开累积调用

  4. 现在factorial(1)可以通过将factorial(0)的副本乘以n1)的副本并将其返回来完成。

  5. ...让factorial(2)完成并乘以2 ...

  6. ...冲洗重复...

  7. 或者用另一种方式显示嵌套(递归):

    factorial(5)
        return 5 * factorial(4)
            return 4 * factorial(3)
                return 3 * factorial(2)
                    return 2 * factorial(1)
                        return 1 * factorial(0)
                            return 1

    因为你无法获得足够的图表(或者至少不能):

    factorial(5)    factorial(4)    factorial(3)    factorial(2)    factorial(1)    factorial(0)
        calls ---------->
                        calls ---------->
                                        calls ---------->
                                                        calls ---------->
                                                                        calls ----------->
                                                                                         n is 0, so
                                                                                         returns 1
                                                                                                 |
                                                                        returns 1 * 1<-----------+
                                                                                = 1
                                                                                  |
                                                        returns 2 * 1<------------+
                                                                = 2
                                                                  |
                                        returns 3 * 2<------------+
                                                = 6
                                                  |
                        returns 4 * 6<------------+
                                = 24
                                  |
        returns 5 * 24<-----------+
                = 120
    
    Result: 120

    旁注:该功能不允许使用负数;它可能在开始时使用警卫......

答案 1 :(得分:3)

n更改:

5 * factorial(5-1) = 5 * 4 * factorial(4-1) = 5 * 4 * 3 * factorial(3-1) = 5 * 4 * 3 * 2 * factorial(1-1) = 5 * 4 * 3 * 2 * 1

为了使这个功能更好,你可以在n等于1时停止它,因为阶乘1是1:

var factorial = function(n){
   if (n === 1 || n === 0)
       return 1;
   else
       return n * factorial(n - 1); 
};

答案 2 :(得分:2)

这个函数说:如果你想计算阶乘(5),那么,那真的只是

5 * factorial(4)

如果你想计算阶乘(4),那真的只是4 *阶乘(3)

5 * 4 * factorial(3)

和关于阶乘(3)的事情是它真的只是3 *阶乘(2)

5 * 4 * 3 * factorial(2)

等等。但是当你得到阶乘(0)时,函数最终停止(因为if n == 0情况)并返回1,没有任何进一步的递归。所以你得到了

5 * 4 * 3 * 2 * 1

return n * factorial(n - 1)转换为(在第一次运行时),“return(5 * 4!)”。它没有做任何5次。

答案 3 :(得分:1)

  

如果我们在示例中使用5之类的,那么一旦我们得到else语句就不会

     

返回n * factorial(n - 1);

     

转换为'返回5乘以阶乘函数(5-1); 5次......

不,它会转换为'返回n乘以阶乘函数(n-1)'(5次,因为n从5开始,递减并输入else子句直到达到0)。

  1. 首次进入该功能时,n等于5.
  2. if子句检查n是否等于0.它不是,所以它转到:
  3. else子句。这意味着'返回5乘以阶乘函数(你所在的)(5 - 1)。
  4. 当您输入阶乘函数时,n现在为4.
  5. 重复所有这些步骤,直到n等于0. if子句将为true,函数将返回1.

    因此从factorial(0)返回1。因子(1)返回1 *阶乘(0),因此1 * 1 = 1。

    因子(2)返回2 *阶乘(1),因此2 * 1 = 2.

    因子(3)返回3 *阶乘(2),因此3 * 2 = 6。

    因子(4)返回4 *阶乘(3),因此4 * 6 = 24。

    因子(5)返回5 *阶乘(4),因此5 * 24 = 120。