神奇的遞迴!一文讀懂函式遞迴(python實現)
阿新 • • 發佈:2018-12-09
遞迴是指函式在定義中呼叫函式自身的方式,是數學歸納法思維的程式設計體現。
是不是有點暈,來看例1:
在上式對階乘的定義中,計算n!需要知道(n-1)!,計算(n-1)!需要知道(n-2)!......以此類推,一直到計算2!需要知道1!,而從上面的定義中可知1!=1。那麼,2!就可以算出來了,3!, 4! ......這樣反向進行運算,最後就可以得到n!了。
從這個例子可以看出,遞迴有兩個關鍵特徵:
- 鏈條:計算過程存在鏈條,例1中的鏈條是n! = n(n-1)!
- 基例:存在一個或多個不需要再次遞迴的基例,例1的基例是1! = 1
def fact(n): if n == 0: return 1 # 基例 else: rturn n*fact(n-1) # 鏈條
從這段簡單的程式碼可以得到遞迴實現的一般套路:函式+分支語句
- 遞迴本身是個函式,需要通過函式定義方式描述
- 在函式內部,採用分支語句對輸入引數進行判斷,針對基例和鏈條分別編寫對應程式碼
在上述程式碼中,5!的階乘是怎麼實現的呢?遞迴先重複的複製自身並不斷代入更小的引數,就是下圖藍色箭頭所示;當輸入引數下降到基例n=0時,將基例的值代入再不斷往前推最終得到n=5的階乘,如下圖紅色箭頭所示。
再來看看其它幾個例子:
# 例2:字串反轉( 不準用s[::-1]哈哈哈) def rvs(s): if s == '': return s # 基例 else: return rvs(s[1:]) + s[0] # 鏈條
# 例3:斐波那契數列
def f(n):
if n == 1 or n == 2:
return 1
else:
return f(n - 1) + f(n - 2)
for i in range(1, 31):
print(f(i))
# 例4:漢諾塔問題 # 問題描述: # 將一摞從小到大堆放的圓盤從src(source)杆移動到dst(destination)杆 # 可以利用mid(middle)杆,一次移動一個,小的在上面 count = 0 # 移動次數 def hanoi(n, src, dst, mid): # n 圓盤數量;src 原杆; dst 目標杆; mid 中間杆 global count # 全域性變數宣告 if n == 1: print('{}:{}->{}'.format(n, src, dst)) count += 1 else: # 遞迴鏈條,呼叫了兩次自身函式 hanoi(n-1, src, mid, dst) # 把n-1個從src移動到mid print('{}:{}->{}'.format(n, src, dst)) # 把第n個圓盤從src移動到dst count += 1 hanoi(n-1, mid, dst, src) # 把mid上的n-1個圓盤移動到dst