遞歸(recursion):
程序調用自身的編程技巧。把問題轉化為規模縮小了的同類問題的子問題。然后遞歸調用函數(或過程)來表示問題的解
遞歸滿足2個條件:
1)有反復執行的過程(調用自身)
2)有跳出反復執行過程的條件(遞歸出口)
如何思考遞歸
(此段摘於qmdweb的CSDN博客)
在初學遞歸的時候, 看到一個遞歸實現, 我們總是難免陷入不停的驗證之中,比如上面提及的階乘,求解Factorial(n)
時,我們總會情不自禁的發問,Factorial(n-1)
可以求出正確的答案么?接着我們就會再用Factorial(n-2)
去驗證,,,不停地往下驗證直到Factorial(0)
。
對遞歸這樣的不適應,和我們平時習慣的思維方式有關。我們習慣的思維是:已知Factorial(0)
,乘上 1 就等於Factorial(1)
,再乘以 2 就等於Factorial(2)
,,,直到乘到 n。
而遞歸和我們的思維方式正好相反。
那我們怎么判斷這個遞歸計算是否是正確的呢?Paul Graham 提到一種方法,如下:
如果下面這兩點是成立的,我們就知道這個遞歸對於所有的 n 都是正確的。
當 n=0,1 時,結果正確;
假設遞歸對於 n 是正確的,同時對於 n+1 也正確。
這種方法很像數學歸納法,也是遞歸正確的思考方式,上述的第 1 點稱為基本情況,第 2 點稱為通用情況。
在遞歸中,我們通常把第 1 點稱為終止條件,因為這樣更容易理解,其作用就是終止遞歸,防止遞歸無限地運行下去。
漢諾塔問題描述為:
有三根桿子 A,B,C。A 桿上有 N 個穿孔圓盤,盤的尺寸由上到下依次變大,B,C 桿為空。要求按下列規則將所有圓盤移至 C 桿:
每次只能移動一個圓盤,大盤不能疊在小盤上面。
思路(如何移?最少要移動多少次?)
首先看下基本情況,即終止條件:N=1 時,直接從 A 移到 C。
再來看下通用情況:當有 N 個圓盤在 A 上(N>1),我們怎么移動 N個圓盤到 C 杠上呢?很簡單,我們首先用將 N-1個圓盤移動到 C 上的方法將 N 個圓盤都移動到 B 上,然后再把第 N個圓盤(只有一個)移動到 C 上,再用同樣的方法將在 B 杠上的 N -1個圓盤移動到 C 上,問題解決。
Python代碼實現 (3個盤子移動過程如下) 與C語言類似
def hanoi(n,a,b,c):
if n==1 :
print(a,'->',c)
else :
hanoi(n-1,a,c,b)
hanoi(1,a,b,c)
hanoi(n-1,b,a,c)
hanoi(3,'A','B','C')