递归资料
(很用的關(guān)于遞歸的講解:)
| 淺析程序設(shè)計(jì)中的遞歸算法熱 |
| [ 作者:晏素芹?|?轉(zhuǎn)貼自:本站原創(chuàng)?|?點(diǎn)擊數(shù):1116?|?更新時間:2011-3-15?|?文章錄入:imste???2010年?第?17?期 ] |
| (徐州市廣播電視大學(xué),江蘇 徐州 221006) 遞歸在計(jì)算機(jī)科學(xué)和數(shù)學(xué)中是一個很重要的工具, 它在程序設(shè)計(jì)語言中用來定義句法, 在 數(shù)據(jù)結(jié)構(gòu)中用來解決表或樹形結(jié)構(gòu)的搜索和排序等問題。另外,遞歸在計(jì)算方法、運(yùn)籌學(xué)模 型、行為策略和圖論的研究中都得到了廣泛的應(yīng)用。 若一個對象部分地包含它自己,或用它自己給自己定義, 則稱這個對象是遞歸的;在程序設(shè) 計(jì)中,若一個過程直接地或間接地調(diào)用自己,則稱這個過程是遞歸的過程。在定義一個過程 或函數(shù)時出現(xiàn)了調(diào)用本過程或函數(shù)的成分, 即調(diào)用自己本身,稱之為直接遞歸,若過程或 函數(shù)P 調(diào)用過程或函數(shù)Q,而Q 調(diào)用P,稱之為間接遞歸。對于“問題定義是遞歸的, 數(shù)據(jù) 結(jié)構(gòu)是遞歸的, 問題解法是遞歸的”這3種情況, 都可以采用遞歸方法來處理。 遞歸算法的本質(zhì)是把一個大型復(fù)雜的問題層層轉(zhuǎn)化為若干與原問題相似的規(guī)模較小的問題來 處理,當(dāng)規(guī)模小到一定程度時,可以直接得出它的解,這樣通過遞推就可得到原來問題的解 。遞歸調(diào)用的次數(shù)必須是有限的,必須有遞歸結(jié)束的條件。遞歸算法的執(zhí)行過程分為兩步 ,第一步是從目標(biāo)出發(fā)追溯到源頭,稱為回溯。第二步是從源頭逐步回代達(dá)到目標(biāo),稱為遞 推。由于存在遞推,在回溯時,必須保留其返回的地址與參數(shù),使程序能夠返回到調(diào)用處繼 續(xù)執(zhí)行,這一步是系統(tǒng)通過設(shè)置棧來實(shí)現(xiàn)的,程序設(shè)計(jì)者無需對棧進(jìn)行管理。 適宜用遞歸算法求解的問題的充要條件是:問題具有某種可借用的類同自身的子問題描述的 性質(zhì);某一有限步的子問題有直接的解存在。 遞歸過程或遞歸函數(shù)的參數(shù)值在遞歸過 程中必須是按規(guī)律變化的,且參數(shù)值的增/ 減方向應(yīng)與遞歸終止條件相匹配,這樣才能控制 遞歸調(diào)用。 4 遞歸算法的實(shí)例 例1:用遞歸函數(shù)編程求n 的階乘n!。 階乘函數(shù)的遞歸定義如下: 這種定義方法是用階乘函數(shù)自身定義了階乘函數(shù)。由于n!和(n-1)!都是同一個問題的求解, 因此可將n!用遞歸函數(shù)來描述。程序代碼如下: long f(int n) { if ( n = = 0 ) return 1;//遞歸的終止條件及相應(yīng)的操作 else return n * f (n-1);//遞歸調(diào)用 } 例2:中序遍歷二叉樹的遞歸算法。 void Inorder ( BTreeNode * BT ) { if ( BT != NULL ) { Inorder ( BT- > lchild); Visit (BT) ; Inorder ( BT- >rchild); } } 遞歸的執(zhí)行依賴系統(tǒng)堆棧的支持,遞歸的執(zhí)行過程主要分為兩步,回溯(逐層深入遞歸調(diào)用)和 遞推(層層向上遞歸返回),在回溯時需要做的工作有:①進(jìn)行斷點(diǎn)保存,局部變量、形式參數(shù) 保存。②控制流程轉(zhuǎn)向遞歸調(diào)用的入口。 在本次遞歸調(diào)用結(jié)束后向上層調(diào)用返回時需要做的工作有:①保存本次調(diào)用的函數(shù)結(jié)果,恢復(fù) 調(diào)用函數(shù)時的局部變量和形式參數(shù)。②根據(jù)遞歸調(diào)用時的斷點(diǎn)地址將控制流程轉(zhuǎn)回到調(diào)用函 數(shù)中遞歸調(diào)用的下一行代碼處繼續(xù)執(zhí)行。 例1:中求解4!的遞歸調(diào)用過程如下圖所示: 綜上所述,遞歸算法的執(zhí)行過程是不斷地自調(diào)用,直到到達(dá)遞歸出口才結(jié)束自調(diào)用過程;到 達(dá)遞歸出口后,遞歸算法開始按最后調(diào)用的過程最先返回的次序返回;返回到最外層的調(diào)用 語句時遞歸算法執(zhí)行過程結(jié)束。 遞歸算法在執(zhí)行時,存在多次進(jìn)棧和出棧,流程的跳轉(zhuǎn)和返回,甚至?xí)霈F(xiàn)多次重復(fù)計(jì)算, 從 而影響執(zhí)行效率。還有一些高級程序設(shè)計(jì)語言沒有提供遞歸的機(jī)制和手段。因此,有些時候 將遞歸算法非遞歸化是有必要的。 非遞歸化最重要的是理解遞歸的執(zhí)行過程。對于一般的遞歸算法,可以利用以下兩種方法對 其進(jìn)行非遞歸化。 如果遞歸調(diào)用語句是函數(shù)的最后一條執(zhí)行語句, 則稱這種遞歸調(diào)用為尾遞歸。當(dāng)遞歸調(diào)用進(jìn) 入內(nèi)層時, 外層上與各形式參數(shù)對應(yīng)的實(shí)際參數(shù)值和返回地址都會被編譯系統(tǒng)自動保存下來 , 以備返回時使用。對于尾遞歸, 調(diào)用返回時, 其后已沒有執(zhí)行語句了。因而外層的實(shí)際參 數(shù)值不會再用到, 故沒有必要保留。此外, 由于遞歸調(diào)用語句是最后一條可執(zhí)行語句, 返回 地址肯定在函數(shù)末尾, 故其返回地址也沒有必要保留下來。對于這種情況, 關(guān)鍵是從遞歸調(diào) 用出發(fā), 從上而下遞歸到底, 找到遞歸的終止條件, 然后用循環(huán)實(shí)現(xiàn)遞歸算法的非遞歸化。 例3:求n的階乘n!的遞歸算法的非遞歸化。 例1中給出了求n的階乘n!的遞歸算法 從上而下遞歸: f(n)=n*f(n-1) f(n-1)=(n-1)*f(n-2) f(n-2)=(n-2)*f(n-3) : : f(2)=2*f(1) f(1)=1*f(0) f(0)=1 設(shè)最終結(jié)果用f表示,由遞歸的終止條件“n=0時,結(jié)果為1”知,f的初始值=1。由此,可從 下而上地用循環(huán)實(shí)現(xiàn)求f(i),其中i從1到任意正整數(shù)n,f隨著i的變化而變化,其非遞歸算法 如下: long f ( int n ) {int i; long f =1; for ( i=1; i<=n; i++) f =f * i; return f; } 類似的情形很多, 如求2 個正整數(shù)的最大公約數(shù)和求Fibonacci 數(shù)列等。 如果遞歸調(diào)用語句不是函數(shù)中的最后一個語句, 則稱該遞歸調(diào)用為非尾遞歸。對于非尾遞歸 調(diào)用中的入口地址, 計(jì)算機(jī)隱含地自動設(shè)置堆棧, 保留調(diào)用入口地址, 供遞歸返回使用。而 用非遞歸方法, 堆棧是人為設(shè)定, 顯現(xiàn)在程序中, 功能與遞歸算法相同。 由二叉樹的遞歸算法的執(zhí)行過程知,在二叉樹非空時,首先訪問根的左子樹,再訪問根,最后訪 問根的右子樹;訪問根的左子樹時,先要訪問左子樹根的左子樹,再訪問左子樹的根,其次再訪 問左子樹根的右子樹……,如此遞歸下去,一直到樹的最左下結(jié)點(diǎn)被訪問(向左下搜索時,將當(dāng) 前結(jié)點(diǎn)壓入系統(tǒng)棧中保存,以便向上回退時調(diào)出) ,然后訪問最左下結(jié)點(diǎn)的父結(jié)點(diǎn),通過彈棧 獲得最左下結(jié)點(diǎn)的父結(jié)點(diǎn),然后處理該父結(jié)點(diǎn)的右子樹,以此類推,循環(huán)直到整棵樹訪問完畢 。 根據(jù)上述對遞歸執(zhí)行過程的分析,其對應(yīng)的非遞歸算法為: void Inorder ( BTreeNode * BT ) {if ( ! BT) return ; Stack *S = Init-Stack() ; while (BT | | ! Empty-Stack(S) ) { while (BT) / / 當(dāng)指針BT非空時入棧 {Push(S , BT) BT = BT - > lchild ; } Pop (S , BT) ; Visit (BT) ; BT = BT - > rchild ; } / / end while (BT| | Empty[JX*2]-[JX-*2]Stack(s) ) }/ / end InOrder () 遞歸算法具有代碼簡潔,思路清晰的優(yōu)點(diǎn),是設(shè)計(jì)算法的強(qiáng)有力工具。一般而言,遞歸程序的 執(zhí)行效率低于非遞歸程序,但非遞歸算法往往難于編寫,容易出錯;理論上,遞歸算法都可以轉(zhuǎn) 化為非遞歸算法,但存在一些算法很難非遞歸化,如復(fù)雜的間接遞歸,因此,要根據(jù)問題需求及 軟件和硬件的環(huán)境等具體情形選擇遞歸還是非遞歸。 |
?
總結(jié)
- 上一篇: 外资对我国企业兼并控制情况的资料
- 下一篇: m3 pcb开孔 螺丝_螺丝过孔工艺孔底