Javascript百學不厭-遞歸
阿新 • • 發佈:2017-07-19
cnblogs 依次 span 就會 nbsp asc 描述 函數返回 call 中存儲調用記錄
,調用函數產生一個調用記錄,最後一步操作 return fac(n - 1, n * total)
雖然偶爾也用過,但是從來沒具體來整理過
普通遞歸:
function fac(n) { if (n === 1) return 1; return n * fac(n - 1); } fac(5) // 120
這是個階乘。但是占用內存,因為:
fac(5)
(5*fac(4))
(5*(4*fac(3)))
(5*(4*(3*fac(2))))
(5*(4*(3*(2*fac(1)))))
(5*(4*(3*2)))
(5*(4*(6)))
(5*24)
120
這裏需要講明的是: 函數調用會產生“調用記錄(存儲著函數的相關信息)”存放在棧中,當有函數返回,對應的調用記錄才會消失,
上述用普通遞歸實現的階乘的執行過程中,不斷的調用自身,導致一直沒有返回,這樣也就不斷的在棧
而當調用自身的次數過多後,就會產生我們常說的“棧溢出”
擬人描述: 就想一個人不斷地借錢(調用自身,不斷向棧中存調用記錄),但是總想著以後再還(一直沒有返回),
當外債積累到超出自己償還能力的時候,就跑路了(棧溢出)
尾遞歸
function fac(n, total) { if (n === 1) return total; return fac(n - 1, n * total); } fac(5, 1) // 120
執行過程如下:
fac(5,1)
fac(4,5)
fac(3,20)
fac(2,60)
fac(1,120)
說明:永遠只有一個調用記錄
把當前函數的計算結果當做參數傳遞給了下一個自身調用,這樣第一個函數調用產生的調用記錄就消失了,因為它執行完了
依次類推,就不會溢出
尾遞歸:函數的最後一步是執行一個函數
參考來自:阮老師
Javascript百學不厭-遞歸