遞歸的定義
函數定義中調用函數自身的方式
兩個特性:
- 鏈條:計算過程存在遞歸鏈條
例如,n!=n*(n-1)!,n!與(n-1)!就構成了遞歸鏈條 - 基例:基礎的實例,存在一個或多個不需要再次遞歸的基例
例如,當n=0時,我們定義它的值爲1這就是一種基例,它與其他的值之間不存在遞歸關係
遞歸的實現
函數+分支語句
遞歸本身是一個函數,需要函數定義方式描述,用函數定義名字,在函數中調用本身。在函數內部,我們要區分哪些是基例,哪些是鏈條,所以我們要使用一個分支語句對輸入參數進行判斷,基例和鏈條,分別編寫對應代碼
def fact(n):
if n == 0:
return 1
else:
return n*fact(n-1)
我們假設參數的初始值爲5,當n等於5,它會返回n*fact(n-1)
也就是執行5×fact(4),但是當前程序並沒有運算fact(4),不知道fact(4)的值,而fact(4)又調用了一個它自身函數,就需要對當前n等於4的時候的值做運算,計算機會開闢一段新的內存,將計算n等於4的函數的運算值
以此類推,當我們最後在計算機中開闢了一個新的內存,計算fact(0)時,它會返回1,得到1 之後就會返回給fact(1)這段函數,fact(1)執行後它的結果會返回給fact(2),最後返回給fact(5)也就實現了遞歸。
字符串反轉
將字符串s反轉後輸出
s[::-1]
這是列表切片中達到字符串反轉的
遞歸方式:
def rvs(s):
if s == "":
return s
else:
return rvs(s[1:]+s[0])
字符串的基例就是字符串的最小形式,那就是空字符串,反轉,就是它自己,如果字符串等於" "
我們就返回它自身,如果字符串s不是空,它的反轉是什麼呢,如果要實現遞歸過程,那就需要遞歸鏈條,遞歸鏈條很重要的就是,當前操作和之前的一步之間的關係,爲了將字符串s進行反轉,我們可以將一個字符串的首字符放在其餘字符的後面,構成反轉,將其餘字符看成是反轉後的字符,這樣我們就完成一次字符串的反轉
斐波那契數列
df f(n):
if n == 1 or n == 2 :
return 1
else :
return f(n-1)+f(n-2)
漢諾塔問題
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)
print("{}:{}->{}".format(n,src,dst))
count += 1
hanoi(n-1,mid,dst,src)
n = eval(input())
hanoi(n,"A","B","C")
遞歸語句中主要在於尋找基例和鏈條,鏈條主要是當前操作與前一步操作的關係,在漢諾塔問題中,當前操作是藉助過度柱子將盤子從源柱子挪到目的柱子,而前一步操作,源柱子變成了過渡柱子,即藉助源柱子,將剩餘盤子從過渡柱子挪至目的柱子,仔細分析有兩個盤子的時候,挪動最下面的盤子的過程就是當前操,挪動最上面盤子的過程就是前一步操作。