在定義一個過程或函數(shù)時出現(xiàn)調(diào)用本過程或本函數(shù)的成分,成為遞歸珠闰。調(diào)用自身稱為直接遞歸惜浅,若q調(diào)用p,p調(diào)用q,則稱為間接遞歸。
尾遞歸伏嗜,在函數(shù)中遞歸調(diào)用是最后一句執(zhí)行語句坛悉。
例題:求n的階乘的遞歸函數(shù)
例題:Fibonacci數(shù)列
使用遞歸時的三種情況,
1.0定義是遞歸的阅仔。
有許多數(shù)學公式吹散,數(shù)列等的定義是遞歸的。
2.數(shù)據(jù)結(jié)構(gòu)是遞歸的
例題八酒,求單鏈表所有節(jié)點數(shù)據(jù)域的和空民。
3.問題的求解方法是遞歸的。
例題羞迷,hanoi問題求解界轩。
def Hanoi(n,X,Y,Z):
if n == 1:
print('\t將第{0}個盤片從{1}移動到{2}\n'.format(n,X,Z))
else:
Hanoi(n-1, X,Z,Y)
print('\t將第{0}個盤片從{1}移動到{2}\n'.format(n,X,Z))
Hanoi(n-1, X,Z,Y)
遞歸模型的結(jié)構(gòu),包含遞歸出口和遞歸體衔瓮。前者確定遞歸到何時結(jié)束浊猾,后者確定遞歸求解時的遞推關(guān)系。
遞歸出口:f(n)? = 1? n =1
遞歸出口的一般格式如下:f(s1) =m1
S1和m1均為常量热鞍,有些遞歸問題可能有幾個遞歸出口
遞歸體:f(n)? =n*f(n-1) n>1
遞歸的思路是把一個不能或不好直接求解的"大問題"轉(zhuǎn)換成一個或幾個"小問題"來解決葫慎,再把這些"小問題"進一步分解成更小的"小問題"來解決,如此分解薇宠,直至每個小問題都可以直接解決了偷办,此時分解到遞歸出口。但是遞歸分解不是隨意地分解澄港,遞歸分解要保證"大問題"和小問題相似椒涯,求解過程和環(huán)境都相似。
遞歸函數(shù)直接或間接調(diào)用自身回梧。雖然每次調(diào)用的是相同的子程序废岂,但它的參量,輸入數(shù)據(jù)等均有變化狱意,并且在正常情況下湖苞,隨著調(diào)用的不斷深入,必定會出現(xiàn)調(diào)用到某一層的函數(shù)時髓涯,不再執(zhí)行遞歸調(diào)用而終止函數(shù)的執(zhí)行袒啼,遇到遞歸出口。
遞歸調(diào)用是函數(shù)嵌套調(diào)用的一種特殊情況,它是調(diào)用自身代碼蚓再,因為也可以理解成每一次遞歸調(diào)用就是自身代碼的一個復制品滑肉。由于每次調(diào)用時它的參量和局部變量均不相同因而也就保證了各個復制件執(zhí)行時的獨立性。
但這些調(diào)用在內(nèi)部實現(xiàn)時并不是每次調(diào)用真的需要去復制一個復制件存放到內(nèi)存中摘仅,而是才用代碼共享的方式靶庙,調(diào)用同一個函數(shù)的代碼,系統(tǒng)為每次調(diào)用開辟一組存儲單元娃属,用來存放本次調(diào)用的返回地址和被中斷的函數(shù)的參量值六荒。這些單元以棧的形式存放,每調(diào)用一次就進棧一次矾端,當返回執(zhí)行出棧操作時掏击,把當前棧頂保留的值送回相應的參量中進行恢復,并按棧頂中的返回地址秩铆,從斷點繼續(xù)執(zhí)行砚亭。
例題:采用遞歸算法求實數(shù)數(shù)組A中的最小值
例題:字符串求逆的遞歸算法
例題:求順序表中最大元素,利用遞歸的方法
例題:假設二叉樹采用二叉存儲結(jié)構(gòu)殴玛,根節(jié)點指針為b捅膘,求該二叉樹所有的節(jié)點個數(shù)。
例題:在n×n的方格棋盤上滚粟,放置n個皇后寻仗,要求每個皇后不同行,不同列凡壤,不用左右對角線
遞歸的時間效率比較差署尤,有時候我們希望用遞歸算法分析問題,用非遞歸算法具體求解問題亚侠。
把遞歸算法轉(zhuǎn)換成非遞歸算法有如下兩種基本方法:
1.對于尾遞歸和單向遞歸的算法沐寺,可以使用循環(huán)結(jié)構(gòu)的算法代替。
2.用棧模擬系統(tǒng)的運行過程盖奈,通過分析只保存必要保存的信息,從而用非遞歸算法替代遞歸算法狐援。
單向遞歸是指遞歸函數(shù)中雖然有一處以上的遞歸調(diào)用語句钢坦,但各次遞歸調(diào)用語句的參數(shù)只和主調(diào)用函數(shù)有關(guān),相互之間參數(shù)無關(guān)啥酱,并且這些遞歸調(diào)用語句也和尾遞歸一樣處于算法的最后爹凹。