普通遞迴與優化遞迴

2022-04-29 08:09:09 字數 1169 閱讀 5724

function factorial(n) 

factorial(5) // 120

上面**是乙個階乘函式,計算n的階乘,最多需要儲存n個呼叫記錄,複雜度 o(n) 。

如果改寫成尾遞迴,只保留乙個呼叫記錄,複雜度 o(1) 。

函式呼叫自身,稱為遞迴。如果尾呼叫自身,就稱為尾遞迴。

遞迴非常耗費記憶體,因為需要同時儲存成千上百個呼叫幀,很容易發生「棧溢位」錯誤(stack overflow)。但對於尾遞迴來說,由於只存在乙個呼叫幀,所以永遠不會發生「棧溢位」錯誤

function factorial(n, total) 

factorial(5, 1) // 120

還有乙個比較著名的例子,就是計算 fibonacci 數列,也能充分說明尾遞迴優化的重要性。

非尾遞迴的 fibonacci 數列實現如下。

function fibonacci (n) ;

return fibonacci(n - 1) + fibonacci(n - 2);}

fibonacci(10) // 89

fibonacci(100) // 堆疊溢位

fibonacci(500) // 堆疊溢位

尾遞迴優化過的 fibonacci 數列實現如下。

unction fibonacci2 (n , ac1 = 1 , ac2 = 1) ;

return fibonacci2 (n - 1, ac2, ac1 + ac2);}

fibonacci2(100) // 573147844013817200000

fibonacci2(1000) // 7.0330367711422765e+208

fibonacci2(10000) // infinity

由此可見,「尾呼叫優化」對遞迴操作意義重大,所以一些函式式程式語言將其寫入了語言規格。es6 是如此,第一次明確規定,所有 ecmascript 的實現,都必須部署「尾呼叫優化」。這就是說,es6 中只要使用尾遞迴,就不會發生棧溢位,相對節省記憶體。

遞迴函式的改寫

function factorial(n, total = 1) 

factorial(5) // 120

普通遞迴與尾遞迴

遞迴就是函式直接或間接呼叫自身。遞迴函式設計時明確三點,一是明確遞迴邊界條件 二是繼續執行遞迴,三是遞迴返回。當不滿足遞迴邊界條件時,遞迴前進,也即繼續執行遞迴。當滿足邊界條件時,遞迴返回。1 資料格式就是遞迴形式,如fibonacci函式等 2 資料結構以遞迴定義,如二叉樹,圖等 3 問題解法是以...

python遞迴 Python 與尾遞迴優化

有很多時候,使用遞迴的方式寫 要比迭代更直觀一些,以下面的階乘為例 def factorial n if n 0 return 1 return factorial n 1 n 但是這個函式呼叫,如果展開,會變成如下的形式 factorial 4 factorial 3 4 factorial 2 ...

遞迴 遞迴的優化

遞迴演算法在工作或者各種資料結構中使用比較頻繁,遞迴演算法的簡化常見有自頂向下還有備忘錄法 自頂向下 t n t1 n t2 n t3 n 25c t1 n r11p1 r12p2 r13p3 r14p4 r15p5 r16p6 r17p7 r18p8 r19p9 t1 n 1 x tau1 t1 ...