2017-02-16 133 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