標籤:簡單 條件 dsa S3 開始 優點 印度 問題 ==
遞迴函式定義:即在函數定義中自己調用自己
- 遞迴就是在過程或函數中自我調用
- 遞迴必須有遞迴出口,即遞迴結束條件
舉個栗子—階乘:
def fact(n): if n == 1: return 1 return n * factorial(n - 1)print(factorial(5))# 120
函數執行過程:
===> fact(5)===> 5 * fact(4)===> 5 * (4 * fact(3))===> 5 * (4 * (3 * fact(2)))===> 5 * (4 * (3 * (2 * fact(1))))===> 5 * (4 * (3 * (2 * 1)))===> 5 * (4 * (3 * 2))===> 5 * (4 * 6)===> 5 * 24===> 120
注意: 使用遞迴函式需要防止棧溢出。 函數調用是通過 棧(stack)這種資料結構實現的,每當進入一個函數調用,棧就會增加一層棧幀,每當函數返回,就會減一層棧幀。由於棧的空間是有限的,遞迴調用次數過多就會導致棧溢出
尾遞迴最佳化:
為了避免棧溢出,可以通過尾遞迴最佳化,尾遞迴實際與迴圈一樣,我們可以迴圈當做是特殊的尾遞迴.
尾遞迴是指,在函數返回的時候,調用自身本身,並且,return語句不能包含運算式。這樣,編譯器或者解譯器就可以把尾遞迴做最佳化,使遞迴本身無論調用多少次,都只佔用一個棧幀,不會出現棧溢出的情況
# 尾遞迴的例子def calc(n): print(n - 1) if n > -50: return calc(n-1)
根據尾遞迴定義,我們的階乘就不是尾遞迴了
def fact(n): if n == 1: return 1 return n * factorial(n - 1)
因為返回語句是一個乘法操作 ,return n * factorial(n - 1)
引入了乘法操作。
- 尾遞迴調用時,如果做了最佳化,棧不會增長,因此,無論多少次調用也不會導致棧溢出 .
- 使用遞迴函式的優點是邏輯簡單清晰,缺點是過深的調用會導致棧溢出。
- 針對尾遞迴最佳化的語言可以通過尾遞迴防止棧溢出。尾遞迴事實上和迴圈是等價的,沒有迴圈語句的程式設計語言只能通過尾遞迴實現迴圈。
- Python標準的解譯器沒有針對尾遞迴做最佳化,任何遞迴函式都存在棧溢出的問題。^_^
漢諾塔問題
漢諾塔:漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石砫子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
def move(n,a,b,c): if n == 1: print(‘move‘, a, ‘-->‘, c) else: move(n-1,a,c,b) move(1,a,b,c) move(n-1,b,a,c)move(3,‘A‘,‘B‘,‘C‘)# 列印結果:# move A --> C# move A --> B# move C --> B# move A --> C# move B --> A# move B --> C# move A --> C
python—遞迴函式