Python進階 —— 尾遞歸

作者是一名沉迷于Python無法自拔的蛇友,為提高水平,把Python的重點和有趣的實例發(fā)在簡書上。

尾遞歸

如果一個函數(shù)中所有遞歸形式的調(diào)用都出現(xiàn)在函數(shù)的末尾,我們稱這個遞歸函數(shù)是尾遞歸的。當遞歸調(diào)用是整個函數(shù)體中最后執(zhí)行的語句且它的返回值不屬于表達式的一部分時,這個遞歸調(diào)用就是尾遞歸。尾遞歸函數(shù)的特點是在回歸過程中不用做任何操作,這個特性很重要,因為大多數(shù)現(xiàn)代的編譯器會利用這種特點自動生成優(yōu)化的代碼。
(來源于不說人話的某度)

下面是筆者的個人理解:把計算出的值存在函數(shù)內(nèi)部(當然不止尾遞歸)是其計算方法,從而不用在棧中去創(chuàng)建一個新的,這樣就大大節(jié)省了空間。函數(shù)調(diào)用中最后返回的結(jié)果是單純的遞歸函數(shù)調(diào)用(或返回結(jié)果)就是尾遞歸。

實例

實例還是和筆者的上一篇文章相同,建議讀者閱讀 Python —— 遞歸

  1. 階乘

常規(guī)遞歸階乘:

def factorial(n):  
    if n == 0:
        return 1
    return factorial(n - 1) * n

我們來看一下執(zhí)行過程:

factorial(4)  
factorial(3) * 4  
factorial(2) * 3 * 4  
factorial(1) * 2 * 3 * 4  
factorial(0) * 1 * 2 * 3 * 4  
1 * 1 * 2 * 3 * 4  
1 * 2 * 3 * 4  
2 * 3 * 4  
6 * 4  
24 

但是如果把上面的函數(shù)寫成如下形式:

def factorial(n, acc=1):  
    if n == 0:
        return acc
    return factorial(n - 1, n * acc)

我們再看下執(zhí)行過程:

factorial(4, 1)  
factorial(3, 4)  
factorial(2, 12)  
factorial(1, 24)  
factorial(0, 24)  
24 

很直觀的就可以看出,這次的 factorial 函數(shù)在遞歸調(diào)用的時候不會產(chǎn)生一系列逐漸增多的中間變量了,而是將狀態(tài)保存在 acc 這個變量中。而這種形式的遞歸,就叫做尾遞歸。

  1. 斐波那契數(shù)列

常規(guī)遞斐波那契數(shù)列:

def fib(n):
    if n < 2:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

而尾遞歸:

def fib_tail(n, r, t):
    if n == 1:
        return r
    else:
        return fib_tail(n - 1, t, r + t)

一下子就充滿了逼格,還高效了許多,何樂而不為呢!

總結(jié)

可以看出,在每次遞歸調(diào)用的時候,都會產(chǎn)生一個臨時變量,導(dǎo)致進程內(nèi)存占用量增大一些。這樣執(zhí)行一些遞歸層數(shù)比較深的代碼時,除了無謂的內(nèi)存浪費,還有可能導(dǎo)致著名的堆棧溢出錯誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容