以遞迴方式實現階加函式的實現:
int recsum(int n)
以尾遞迴方式實現階加函式的實現:
int tailrecsum(int n, int res=0)
遞迴(迭代):
recsum(5)
5 + recsum(4)
5 + (4 + recsum(3))
5 + (4 + (3 + recsum(2)))
5 + (4 + (3 + (2 + recsum(1))))
5 + (4 + (3 + (2 + 1)))
5 + (4 + (3 + 3))
5 + (4 + 6)
5 + 10
15
尾遞迴:
tailrecsum(5, 0)
tailrecsum(4, 5)
tailrecsum(3, 9)
tailrecsum(2, 12)
tailrecsum(1, 14)
tailrecsum(0, 15)
15
尾遞迴的判斷標準是函式執行最後一步是否只呼叫自身,而不是是否在函式的最後一行呼叫自身。
這是尾遞迴:
function f(x)
這不是尾遞迴:
function f(x)
在來看乙個例子:
計算斐波那契數列第n項
//遞迴
int fibonacci(int n)
//尾遞迴
int fibonacci_tail(int n, int ret1 = 0, int ret2 = 0)
如果拿fib(6)=6+fib(5)作為例子的話,普通的遞迴算到最後,記憶體中需要儲存6+5+4+3+2+fib(1),而尾遞迴則是20+fib(1)。前者耗費了大量記憶體。
所以,尾遞迴,比線性遞迴多乙個引數,這個引數是上一次呼叫函式得到的結果;
所以,關鍵點在於,尾遞迴每次呼叫都在收集結果,避免了線性遞迴不收集結果只能依次展開消耗記憶體的壞處。
使用尾遞迴可以帶來乙個好處:因為進入最後一步後不再需要參考外層函式(caller)的資訊,因此沒必要儲存外層函式的stack,遞迴需要用的stack只有目前這層函式的,因此避免了棧溢位風險。
遞迴和尾遞迴的區別
一 遞迴 1.定義 在電腦科學領域中,遞迴式通過遞迴函式來實現的。程式呼叫自身的程式設計技巧稱為遞迴 recursion 乙個過程或函式在其定義或說明中有直接或間接呼叫自身的一種方法,它通常把乙個大型複雜的問題層層轉化為乙個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題過程...
遞迴和尾遞迴
c語言中編譯預處理的三種形式的命令 巨集定義,檔案包含,條件編譯命令。1 巨集定義主要是 define,undef 如下 define pi 3.1415926 不帶引數的巨集定義 define max a,b a b?a b 帶引數的巨集定義 說明 巨集定義在c語言與c 語言中是相通的。下面舉例說...
尾遞迴和線性遞迴
線性遞迴 fac 0 1 fac n n fac n 1 尾遞迴 fac 0,sum sum fac n,sum fac n 1,sum n 尾遞迴定義 函式最後一步呼叫自身,即最後一行 一定是對於自己的乙個遞迴呼叫。erlang尾遞迴這樣帶來的好處是可以讓編譯器做到將遞迴優化,轉化為跳轉指令而不是...