1. 程式人生 > >Python——遞迴函式

Python——遞迴函式

一. 遞迴函式

遞迴函式就是函式在內部呼叫自身。

必須有一個明確的遞迴結束條件,稱為遞迴出口。

注意: 切勿忘記遞迴出口,避免函式無限呼叫。

函式呼叫自身的實現:

其實函式每次被呼叫時都會建立一個新名稱空間,也就是當函式呼叫“自身”時,實際上執行的是兩個不同的函式(也可以說一個函式具有兩個不同的名稱空間)。

【例】定義階乘函式

遞迴實現:

>>> def fact(n):
...     if n == 1:
...             return 1
...     else:
...             return  n * fact( n-1 )
...
>>>
>>> fact(1)
1
>>> fact(2)
2
>>> fact(4)
24
>>> fact(5)
120

fact(5) 計算過程:

factorial(5)                        # 第 1 次呼叫使用 5
5 * factorial(4)                    # 第 2 次呼叫使用 4
5 * (4 * factorial(3))              # 第 3 次呼叫使用 3
5 * (4 * (3 * factorial(2)))        # 第 4 次呼叫使用 2
5 * (4 * (3 * (2 * factorial(1))))  # 第 5 次呼叫使用 1 
5 * (4 * (3 * (2 * 1)))             # 從第 5 次呼叫返回
5 * (4 * (3 * 2))                   # 從第 4 次呼叫返回
5 * (4 * 6)                         # 從第 3次呼叫返回
5 * 24                              # 從第 2 次呼叫返回
120                                 # 從第 1 次呼叫返回

迭代實現:

>>> def fact(n):
...     result = 1
...     for i in range(2,n+1):
...             result *= i
...     return result
...
>>>
>>> fact(1)
1
>>> fact(2)
2
>>> fact(5)
120

遞迴的優缺點:

優點:

  • 遞迴使程式碼看起來更加整潔、優雅
  • 可以用遞迴將複雜任務分解成更簡單的子問題
  • 使用遞迴比使用一些巢狀迭代更容易

缺點:

  • 遞迴的邏輯很難除錯、跟進
  • 遞迴呼叫的代價高昂(效率低),因為佔用了大量的記憶體和時間。

二.  尾遞迴

使用遞迴函式需要注意防止棧溢位。在計算機中函式呼叫是通過棧這種資料結構實現的。每當進入一個函式呼叫,棧就會加一層棧幀;每當函式返回就會減一層棧幀。由於棧的大小不是無限的,因此遞迴呼叫次數過多會導致棧溢位。

解決遞迴呼叫棧溢位的方法是通過尾遞迴優化。

尾遞迴是指函式返回時呼叫函式本身,並且 return 語句不能包含表示式。這樣,編譯器和直譯器就可以對尾遞迴進行優化。使遞迴本身無論呼叫多少次都只佔用一個棧幀,從而避免棧溢位的情況。

>>> def fact(n):
...     return fact_iter(n,1)
...
>>>
>>> def fact_iter(num , result):
...     if num == 1:
...             return result
...     return fact_iter(num-1 , num * result)
...
>>>
>>>
>>> fact(1)
1
>>> fact(2)
2
>>> fact(5)
120