尾調用、尾遞歸、非尾遞歸的幾個概念及非尾遞歸是否能夠轉換爲尾遞歸。html
tail call指的是一個函數的最後一條語句也是一個返回調用函數的語句,即return的是一個函數,這個函數能夠是另外一個函數,也能夠是自身函數。
def fun_b(x): x = x -1 return x def function_a(x): x = x + 1 return fun_b(x) # 最返回的是函數
函數在return的時候調用自身,這種狀況稱爲尾遞歸,除了調用自身不能有其餘額外的。尾遞歸是遞歸的一種特殊形式,也是是尾調用的一種特殊形式(尾調用最後調用函數自身,就是一個尾遞歸)。尾調用不必定是尾遞歸。
尾遞歸特色:python
def fun_b(x): if x == 1: return x else: return fun_b(x) # 最後返回調用的是自身函數,是尾遞歸,若是寫成`return fun_b(x)+1`則不是尾遞歸
把尾遞歸以外的其餘遞歸調用歸結爲非尾遞歸
普通遞歸函數自身調用次數不少,遞歸層級很深,棧空間爲0(n),尾遞歸優化後棧空間可爲O(1)。下面有例子能夠觀察其棧佔用的不一樣:函數
# 這個是一個非尾遞歸 def normal_sum(x): if x == 1: return x else: return x + normal_sum(x - 1)
調用fun_sum(5)非尾遞歸的棧變化:學習
normal_sum(5) 5 + normal_sum(4) 5 + (4 + normal_sum(3)) 5 + (4 + (3 + normal_sum(2))) 5 + (4 + (3 + (2 + normal_sum(1)))) 5 + (4 + (3 + (2 + 1))) 5 + (4 + (3 + 3)) 5 + (4 + 6) 5 + 10 15
把上面的函數修改成尾遞歸的方式(尾遞歸是把變化的參數傳遞給遞歸函數的變量了):優化
def tail_sum(x, total=0): if x == 0: return total else: return tail_sum(x - 1, total + x)
調用尾遞歸tailrecsum(5, 0)的棧變化:code
tail_sum(5, 0) tail_sum(4, 5) tail_sum(3, 9) tail_sum(2, 12) tail_sum(1, 14) tail_sum(0, 15) 15
經過CPS變換,能夠把非尾遞歸轉換爲尾遞歸。其核心思想就是把
能夠參考這篇博客orm
終身學習!