如何用棧實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換_第1頁
如何用棧實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換_第2頁
如何用棧實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換_第3頁
如何用棧實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換_第4頁
如何用棧實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換_第5頁
已閱讀5頁,還剩7頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

如何用棧實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換一.為什么要學(xué)習(xí)遞歸與非遞歸的轉(zhuǎn)換的實現(xiàn)方法?

1)并不是每一門語言都支持遞歸的.

2)有助于理解遞歸的本質(zhì).

3)有助于理解棧,樹等數(shù)據(jù)結(jié)構(gòu).二.遞歸與非遞歸轉(zhuǎn)換的原理.

遞歸與非遞歸的轉(zhuǎn)換基于以下的原理:所有的遞歸程序都可以用樹結(jié)構(gòu)表示出來.需要說明的是,這個"原理"并沒有經(jīng)過嚴(yán)格的數(shù)學(xué)證明,只是我的一個猜想,不過在至少在我遇到的例子中是適用的.

學(xué)習(xí)過樹結(jié)構(gòu)的人都知道,有三種方法可以遍歷樹:前序,中序,后序.理解這三種遍歷方式的遞歸和非遞歸的表達方式是能夠正確實現(xiàn)轉(zhuǎn)換的關(guān)鍵之處,所以我們先來談?wù)勥@個.需要說明的是,這里以特殊的二叉樹來說明,不過大多數(shù)情況下二叉樹已經(jīng)夠用,而且理解了二叉樹的遍歷,其它的樹遍歷方式就不難了.1)前序遍歷a)遞歸方式:[code:1:1f2a39cc2d]voidpreorder_recursive(BitreeT)/*先序遍歷二叉樹的遞歸算法*/{if(T){visit(T);

/*訪問當(dāng)前結(jié)點*/preorder_recursive(T->lchild);/*訪問左子樹*/preorder_recursive(T->rchild);/*訪問右子樹*/}}[/code:1:1f2a39cc2d]b)非遞歸方式[code:1:1f2a39cc2d]voidpreorder_nonrecursive(BitreeT)/*先序遍歷二叉樹的非遞歸算法*/{initstack(S);push(S,T);

/*根指針進棧*/while(!stackempty(S)){while(gettop(S,p)&&p){/*向左走到盡頭*/visit(p);/*每向前走一步都訪問當(dāng)前結(jié)點*/push(S,p->lchild);}pop(S,p);if(!stackempty(S)){/*向右走一步*/pop(S,p);push(S,p->rchild);

}}}[/code:1:1f2a39cc2d]2)中序遍歷a)遞歸方式[code:1:1f2a39cc2d]voidinorder_recursive(BitreeT)/*中序遍歷二叉樹的遞歸算法*/{if(T){inorder_recursive(T->lchild);/*訪問左子樹*/visit(T);

/*訪問當(dāng)前結(jié)點*/inorder_recursive(T->rchild);/*訪問右子樹*/}}[/code:1:1f2a39cc2d]b)非遞歸方式[code:1:1f2a39cc2d]void

inorder_nonrecursive(BitreeT){initstack(S);/*初始化棧*/push(S,T);/*根指針入棧*/while(!stackempty(S)){while(gettop(S,p)&&p)

/*向左走到盡頭*/push(S,p->lchild);pop(S,p);/*空指針退棧*/if(!stackempty(S)){pop(S,p);visit(p);/*訪問當(dāng)前結(jié)點*/push(S,p->rchild);/*向右走一步*/}}}[/code:1:1f2a39cc2d]3)后序遍歷a)遞歸方式[code:1:1f2a39cc2d]voidpostorder_recursive(BitreeT)/*中序遍歷二叉樹的遞歸算法*/{

if(T){

postorder_recursive(T->lchild);/*訪問左子樹*/

postorder_recursive(T->rchild);/*訪問右子樹*/

visit(T);

/*訪問當(dāng)前結(jié)點*/

}}[/code:1:1f2a39cc2d]b)非遞歸方式[code:1:1f2a39cc2d]typedefstruct{BTNode*ptr;enum{0,1,2}mark;}PMType;

/*有mark域的結(jié)點指針類型*/voidpostorder_nonrecursive(BiTreeT)/*后續(xù)遍歷二叉樹的非遞歸算法*/{PMTypea;initstack(S);

/*S的元素為PMType類型*/push(S,{T,0});

/*根結(jié)點入棧*/while(!stackempty(S)){pop(S,a);switch(a.mark){case0:push(S,{a.ptr,1});

/*修改mark域*/if(a.ptr->lchild)

push(S,{a.ptr->lchild,0});/*訪問左子樹*/break;case1:push(S,{a.ptr,2});

/*修改mark域*/if(a.ptr->rchild)

push(S,{a.ptr->rchild,0});/*訪問右子樹*/break;case2:visit(a.ptr);

/*訪問結(jié)點*/}}}[/code:1:1f2a39cc2d]

4)如何實現(xiàn)遞歸與非遞歸的轉(zhuǎn)換

通常,一個函數(shù)在調(diào)用另一個函數(shù)之前,要作如下的事情:a)將實在參數(shù),返回地址等信息傳遞

給被調(diào)用函數(shù)保存;b)為被調(diào)用函數(shù)的局部變量分配存儲區(qū);c)將控制轉(zhuǎn)移到被調(diào)函數(shù)的入口.

從被調(diào)用函數(shù)返回調(diào)用函數(shù)之前,也要做三件事情:a)保存被調(diào)函數(shù)的計算結(jié)果;b)釋放被調(diào)

函數(shù)的數(shù)據(jù)區(qū);c)依照被調(diào)函數(shù)保存的返回地址將控制轉(zhuǎn)移到調(diào)用函數(shù).

所有的這些,不論是變量還是地址,本質(zhì)上來說都是"數(shù)據(jù)",都是保存在系統(tǒng)所分配的棧中的.

ok,到這里已經(jīng)解決了第一個問題:遞歸調(diào)用時數(shù)據(jù)都是保存在棧中的,有多少個數(shù)據(jù)需要保存

就要設(shè)置多少個棧,而且最重要的一點是:控制所有這些棧的棧頂指針都是相同的,否則無法實現(xiàn)

同步.

下面來解決第二個問題:在非遞歸中,程序如何知道到底要轉(zhuǎn)移到哪個部分繼續(xù)執(zhí)行?回到上

面說的樹的三種遍歷方式,抽象出來只有三種操作:訪問當(dāng)前結(jié)點,訪問左子樹,訪問右子樹.這三

種操作的順序不同,遍歷方式也不同.如果我們再抽象一點,對這三種操作再進行一個概括,可以

得到:a)訪問當(dāng)前結(jié)點:對目前的數(shù)據(jù)進行一些處理;b)訪問左子樹:變換當(dāng)前的數(shù)據(jù)以進行下一次

處理;c)訪問右子樹:再次變換當(dāng)前的數(shù)據(jù)以進行下一次處理(與訪問左子樹所不同的方式).

下面以先序遍歷來說明:[code:1:1f2a39cc2d]voidpreorder_recursive(BitreeT)/*先序遍歷二叉樹的遞歸算法*/{if(T){visit(T);

/*訪問當(dāng)前結(jié)點*/preorder_recursive(T->lchild);/*訪問左子樹*/preorder_recursive(T->rchild);/*訪問右子樹*/}}[/code:1:1f2a39cc2d]

visit(T)這個操作就是對當(dāng)前數(shù)據(jù)進行的處理,preorder_recursive(T->lchild)就是把當(dāng)前數(shù)據(jù)變換為它的左子樹,訪問右子樹的操作可以同樣理解了.

現(xiàn)在回到我們提出的第二個問題:如何確定轉(zhuǎn)移到哪里繼續(xù)執(zhí)行?關(guān)鍵在于一下三個地方:a)確定對當(dāng)前數(shù)據(jù)的訪問順序,簡單一點說就是確定這個遞歸程序可以轉(zhuǎn)換為哪種方式遍歷的樹結(jié)構(gòu);b)確定這個遞歸函數(shù)轉(zhuǎn)換為遞歸調(diào)用樹時的分支是如何劃分的,即確定什么是這個遞歸調(diào)用樹的"左子樹"和"右子樹"c)確定這個遞歸調(diào)用樹何時返回,即確定什么結(jié)點是這個遞歸調(diào)用樹的"葉子結(jié)點".三.三個例子

好了上面的理論知識已經(jīng)足夠了,下面讓我們看看幾個例子,結(jié)合例子加深我們對問題的認(rèn)識.即使上面的理論你沒有完全明白,不要氣餒,對事物的認(rèn)識總是曲折的,多看多想你一定可以明白(事實上我也是花了兩個星期的時間才弄得比較明白得).

1)例子一:[code:1:1f2a39cc2d]f(n)=n+1;(n<2)f[n/2]+f[n/4](n>=2);這個例子相對簡單一些,遞歸程序如下:intf_recursive(intn){intu1,u2,f;毅if(n撫<2)握堡f=n贊+1;光撈else忠{南u1=欲f_rec咸ursiv摩e((in惕t)(n/汽2));溪u2=少f_rec壇ursiv高e((in命t)(n/雷4));骨f=u倉1*u洋2;

羊}競retur謊nf;祥}[/co糧de:1:穴1f2a3淹9cc2d雞]筑

下面部按照我們上原面說的,確乳定好遞歸調(diào)圣用樹的結(jié)構(gòu)并,這一步是千最重要的.愁首先,什么倆是葉子結(jié)點程遠,我們看到裹當(dāng)n<犁2時f=贏n+冬1,這就是丸返回的語句杯,有人問為勵什么不是f抓=u1粗*u2陣,這也是一叉?zhèn)€晴返回的語句卷呀?答案是鳳:這條語句宇是在u1栗=exm協(xié)p1((i乳nt)(n巖/2))和發(fā)u2=絮exmp1蠟((int抱)(n/4于))之后窮執(zhí)行的,是阻這兩條語句厲的父結(jié)點.欺其次,什洽么是當(dāng)前結(jié)微點,由上面鮮的分析,f卡=u1歪*u2暗即是父結(jié)點磁歇.然后,順偏理成章的u都1=e踩xmp1(霉(int)臉(n/2)失)和u2播=exm擠p1((i篩nt)(n旗/4))就煎分別是左子柄樹和右子腹樹了.最后悠,我們可以慈看到,這個答遞歸函數(shù)可捆以表示成后角序遍歷的二央叉調(diào)用樹.瑞好了,樹的栗情況分析崖到這里,下陶面來分析一潮下棧的情況懷,看看我們膝要把什么數(shù)妙據(jù)保存在棧據(jù)中,在上面旁給出的后序渣遍歷的如果豬這個過程你靈沒勝非遞歸程序目中我們已經(jīng)勁看到了要加區(qū)入一個標(biāo)志防域,因此在旗棧中要保存股這個標(biāo)志域豪;另外,u攪1,u2和摔嶄每次調(diào)用遞熟歸函數(shù)時的刪n/2和n岸/4參數(shù)都斷要保存,這富樣就要分別恐有三個棧分損別保存:標(biāo)碧志域,返回軍量負(fù)和參數(shù),不姐過我們可以題做一個優(yōu)化尤,因為在向哭上一層返回喬的時候,參愈數(shù)已經(jīng)沒有孕用了,而返鄉(xiāng)回量也停只有在向上呼返回時才用姜到,因此可溜以把這兩個爺棧合為一個傍棧.如果對逢于上面的分絨析你沒有明冒白,建脅議你根據(jù)這響個遞歸函數(shù)砍寫出它的遞估歸棧的變化庫情況以加深竊理解,再次蓋重申一點:系前期對樹結(jié)地構(gòu)和齊棧的分析是甲最重要的,攔如果你的程泡序出錯,那下么請返回到典這一步來再腦次分析,最戰(zhàn)好把遞歸調(diào)招用樹和銅棧的變化情碎況都畫出來追,并且結(jié)合哥一些簡單的衫參數(shù)來人工肆分析你的算安法到底出錯六在哪里.相

o草k,下面給呈出我花了兩凈天功夫想出宣來的非遞歸番程序(再次后提醒你不要霞氣餒,大家壺都是這么過谷來釋的).沫[code鞏:1:1f侮2a39c感c2d]i阿ntf_疾nonre鞭cursi特ve(in及tn)訪{究ints商tack[恒20],攏flag[吸20],麻cp;心課/*初始?;瘲:蜅m斅抵羔?/培在cp=挺0;捆stack破[0]=積n;連flag[云0]=托0;參while汽(cp企>=0)威{菜switc專h(fla生g[cp]程){弟case爭0:

/孝*訪問的齡是根結(jié)點研*/透if(s督tack[升cp]>綠=2)健{/*蛇左子樹入棧踏*/桑flag[撲cp]=駱1;

驗/*修改廢標(biāo)志域*畢/稅cp++;裳推stack君[cp]寨=(in療t)(st疼ack[c做p-1全]/2桑);恭flag[皺cp]=逮0;暫}els未e{

牧/*否則曾為葉子結(jié)點亡*/憤stack擺[cp]慌+=1;洗闊flag[擊cp]=行2;木}羽break卸;默case桌1:

/僻*訪問的情是左子樹用*/按if(s筒tack[肉cp]>交=2)糾{/*宇右子樹入棧戶*/彩flag[尿cp]=吸2;

爽/*修改頭標(biāo)志域*膀/兼cp+=嘉2;墊stack浩[cp]朗=(in送t)(st限ack[c香p-2速]/4拿);布flag[想cp]=寶1;機}els杯e{

敗/*否則女為葉子結(jié)點現(xiàn)*/貨stack推[cp]統(tǒng)+=1;炕虛flag[獅cp]=王2;段}恰break身;轉(zhuǎn)case陜2:

/件**/濱if(f魄lag[c惡p-1舌]==津2){塌/*當(dāng)前警是右子樹嗎摘?*/畫/*

*如果悟是右子樹,魂那么對某哀一棵子樹的容后序遍歷已婦經(jīng)積

*結(jié)束臉,接下來就抽是對這棵子布樹的根結(jié)點彩的訪問紗

*/晌stack切[cp-獄2]=喉stac甚k[cp]層*st料ack[c壺p-1礙];墓flag[剛cp-項2]=劣2;章cp=玉cp-區(qū)2;塘}els潤e

封/*否則淹退回到后序艦遍歷的上一邀個結(jié)點*符/滅cp--;馳剛break鵝;課}石}譜retur凝nsta扛ck[0]親;盒}[/co辦de:1:憐1f2a3替9cc2d痰]僵涌糧算法分析渾:a)fl惠ag只有三寫個可能值:話0表示第一座次訪問該結(jié)飯點,1表示胖訪問的是左熄子樹,2表某示確已經(jīng)結(jié)束了溫對某一棵子睬樹的訪問,廣可能當(dāng)前結(jié)替點是這棵子以樹的右子樹趨,也可能是利葉子結(jié)點.除b)每鋤遍歷到某個舉結(jié)點的時候雹,如果這個存結(jié)點滿足葉電子結(jié)點的條訓(xùn)件,那么把蘿它的fla斑g域設(shè)為2帶;否則根據(jù)伏柄訪問的是根桶結(jié)點,左子偏樹或是右子嫌樹來設(shè)置f命lag域,碗以便決定下叼一次訪問該蠟節(jié)點時的程騙序轉(zhuǎn)向.估破2)例子二怠土快速排序算跟法雖遞歸算法如脂下:桌[code初:1:1f虧2a39c狂c2d]v亞oids色wap(i煙ntar疫ray[]吵,int遮low,石int胖high)擺抽{楚intt號emp;罪temp奮=arr腥ay[lo粥w];鼓array寇[low]選=ar什ray[h三igh];尚矩array悔[high謝]=t鍵emp;餐}泳intp新artit哀ion(i稻ntar遙ray[]吸,int仆low,赤int蜘high)云定{嬸intp量;衡p=a嫂rray[變low];墾膀while如(跪low<塞high外){選while辱(low柱<hi嘴gh&&票arra震y[hig痕h]>=膏p)

徑high-供-;籃swap(搬array垂,low,所high)喜;多while明(low嘆<hi孝gh&&屠arra帖y[low應(yīng)]

<=禁p)

夠low++獄;孝swap(準(zhǔn)array液,low,倚high)黎;料}宣retur優(yōu)nlow百;脖}蹦void支qsort合_recu離rsive偶(int優(yōu)array暖[],i展ntlo狗w,in驗thig熄h)勸{初intp謹(jǐn);文if(lo延w<h演ig罵h){諒p=p示artit量ion(a感rray,于low,璃high術(shù));抽qsort禾_recu僑rsive雙(arra疲y,lo勤w,p挖-1);碑唇qsort褲_recu括rsive案(arra柏y,p飽+1,羽high)鑰;感}海}[/co藝de:1:楚1f2a3緊9cc2d抗]掀

需要皆說明一下快段速排序的算畜法:pa垃rtiti東on函數(shù)根繭據(jù)數(shù)組中的犧某一個數(shù)把擾數(shù)組劃分為稿兩個部分,賀雹左邊的部分睬均不大于這依個數(shù),右邊趟的數(shù)均不小皆于這個數(shù),史然后再對左慌右兩邊的數(shù)震組再進行劃帽分.這富里我們專注啟于遞歸與非姿遞歸的轉(zhuǎn)換潤,part桐ition銷函數(shù)在非遞混歸函數(shù)中同彎樣的可以調(diào)泄用(其實帥parti箱tion函殃數(shù)就是對當(dāng)賽前結(jié)點的訪諷問).面

再次頂進行遞歸調(diào)爛用樹和棧的銜分析:檢

遞歸閘調(diào)用樹:a談)對當(dāng)前結(jié)組點的訪問是列調(diào)用par僻titio坦n函數(shù);b化)左子樹:奸撐qsort寸_recu免rsive館(arra瞧y,lo抬w,p惱-1);性c)右子樹嗎:qsor裂t_rec五ursiv知e(arr豐ay,p趴+1,扣high化);到d)葉子結(jié)舞點:當(dāng)lo跨w<h摧igh時;左e)可以看抵出這是一個蕉先序調(diào)用的蓋二叉樹答

棧:魯要保存的數(shù)冶據(jù)是兩個表雨示范圍的坐釘標(biāo).括駁掩[code橫:1:1f裝2a39c坑c2d]v準(zhǔn)oidq揮sort_姑nonre鼠cursi雨ve(in攝tarr佛ay[],硬int狂low,岔inth津igh)疤{掉intm丸[50],掏n[50荷],cp島,p;

于醬/*初始潑化棧和棧頂螞指針*/名柏cp=哨0;艱m[0]等=low們;級n[0]俱=hig特h;昏while醬(m[c盞p]<站n[cp]少){澆while剖(m[c雁p]<夾n[cp]絹){/悠*向左走之到盡頭*稻/欲p=p辣artit義ion(a什rray,蟻m[cp期],n[便cp]);咬/*對衛(wèi)當(dāng)前結(jié)點的悅訪問*/富聚cp++;榜柿m[cp]違=m[介cp-國1];賓n[cp]燕=p村-1;兔}盾/*向右庭走一步*截/洞m[cp弦+1]節(jié)=n[c廈p]+云2;飄n[cp前+1]溪=n[c斃p-1他];紹cp++;與輕}脆}[/co桃de:1:鄉(xiāng)1f2a3稈9cc2d亮]昌3)例子三爹搭阿克曼函數(shù)角:猶[code鋸:1:1f管2a39c頑c2d]a禿km(m,扮n)=戴n+崗1;(m搶=0時線)葛

a橋km(m煌-1,適1);(撕n=0評時)宏

a宣km(m旗-1,碌akm(m允,n-掩1));爭(m!蹄=0且n噴!=0錄時)[/c猶ode:1蠟:1f2a氏39cc2達d]

芒腳遞歸算法如忠下:丘[code辰:1:1f肯2a39c男c2d]i觀ntak智m_rec涌ursiv范e(int棉m,i惕ntn)夾破{超intt架emp;撓if(m寬==0弓)

相retur喚n(n執(zhí)+1);晴勒else攻if(n乞==0弓)

爭retur較nakm簽_recu瓶rsive不(m-掙1,1)妨;斜else周{撈temp敲=akm米_recu純rsive立(m,n廈-1)注;究retur乏nakm芳_recu后rsive斗(m-漫1,te晶mp);酷}梳}[/co敵de:1:純1f2a3諒9cc2d嶼]話這個例子相玉對難一些,痰不過只要正啄確的分析遞雹歸調(diào)用樹和蠅棧的變化情適況就不難解常決,先賣個碧關(guān)子,晚上陜再來公布答甜案,感興趣值的可以先想鮮想.關(guān)這個例子相沙對難一些,修不過只要正易確的分析遞么歸調(diào)用樹和乓棧的變化情升況就不難解綢決,先賣個媽關(guān)子,晚上切再來公布答丹案,感興趣橋的可以先想楚想.[/q幟uote:孤782a0聾80549冤]悉遞歸和非遞箭歸,其實年都是一樣的拘.非遞歸需洲要人為構(gòu)建罪維護堆棧.勺遞歸只是系煮統(tǒng)癥在幫你維護矩堆棧而已.養(yǎng)數(shù)據(jù)結(jié)構(gòu)良上說得很清閱楚.用好了,讓我豐們回到遞歸遇與非遞歸的撕世界中,繼扣續(xù)未完的旅皆途.診這道題的難狀點就是確定盞遞歸調(diào)用樹額的情況,因踩為從akm嬌函數(shù)的公式耽可以看到,典有三個遞歸潤調(diào)用,一般漸買而言,有幾菠個遞歸調(diào)用葵就會有幾棵江遞歸調(diào)用的勁子樹,不過豆這只是一般頃的情況,不壟一定準(zhǔn)確,銷也不一定非底要腰機械化的這玻么作,因為混通常情況下望我們可以做忘一些優(yōu)化,探省去其中的睛一些部分,葉這道題就是勺一個例子.老粥

遞息歸調(diào)用樹的商分析:a)亡是當(dāng)m=0獸時是葉子結(jié)倉點;b)左夏子樹是ak乞m(m-捷1,a戶km(m,屠n-綁1))調(diào)用帳中的構(gòu)akm(m崇,n-眾1)調(diào)用妥,當(dāng)這個調(diào)彈用結(jié)束得出棄一個值te會mp時,再贏調(diào)用akm零(m-河1,te親mp),這沫個調(diào)用是右升子樹拉.c)從上伏面的分析可膨以看出,這疼個遞歸調(diào)用乘樹是后序遍杯歷的樹.榨

棧纏的分析:要號保存的數(shù)據(jù)暮是m,n想,當(dāng)n=欠0或凳m=0栗時開始退棧炊,當(dāng)n=松0時把上抄一層棧的m擾值變?yōu)楦鑝-1補,n變?yōu)?畏,當(dāng)m=本0時把上慈一層棧的m伶值變?yōu)?,拌n變?yōu)閚咬+1.從寶這個分析過僚程可以看出屯,我們省略魄了恢當(dāng)n=鴨0時的ak幻m(m-掠1,1座)調(diào)用,原蹲來在系統(tǒng)機態(tài)械化的實現(xiàn)慈遞歸調(diào)用的妥過程中,這娛個調(diào)用也是鼓一棵子樹,猜泊不過經(jīng)過分缺析,我們用線修改棧中數(shù)轎據(jù)的方式進步行了改進.救杯[code吩:1:03咐51fd7調(diào)499]i傲ntak逐m_non融recur舅sive(晉intm籌,int戲n)乓{碎intm天1[50]森,n1[椒50],狗cp;立cp=該0;爪m1[0]杜=m;嬌粗n1[0]味=n;宵杏do{斬while減(m1[淺cp]>捉0){申

/*炒壓棧,直寬到m1[c愚p]=述0*/廢while疑(n1[囑cp]>大0){必

/*及壓棧,直冶到n1[c箱p]=愛0*/蔬cp++;字辰m1[cp互]=m釘1[cp漿-1];凍次n1[cp夕]=n芹1[cp淡-1]爺-1;難}揚/*計算喘akm(m捐-1,魂1),當(dāng)栽n=0盛時*/敘m1[cp刻]=m弊1[cp]帖-1;蓋延n1[cp剪]=1洲;擾}紗/*改棧倦頂為akm妙(m-孝1,n勒+1),割當(dāng)m=剛0時*/克鋤cp--;如局m1[cp穴]=m帥1[cp]咽-1;拘無n1[cp秧]=n促1[cp劃+1]鴉+1;創(chuàng)}whi紐le(c獵p>0表||m皇1[cp]澇>輕0);端retur機nn1[氧0]+帥1;盼}[/co疫de:1:仿0351f支d7499姐]芝三.遞歸程鋼序的分類及滾用途鐘

遞歸佳程序分為兩壇類:尾部遞璃歸和非尾部尤遞歸.上面專提到的幾個暗例子都是非促尾部遞歸,遮在一個選擇鵝分支中有至赴少砍一個的遞歸蜘調(diào)用.相對繩而言,尾部大遞歸就容易推很多了,因音為與非尾部勞遞歸相比,睜每個選擇分處支只有一個鉛遞歸調(diào)用,頑鄙我們在解決道的時候就不床需要使用到那棧,只要循褲環(huán)和設(shè)置好振循環(huán)體就可添以了.下面怠再舉幾個尾襯部遞歸的例客子吧,比較援燕簡單我就不危多說什么了侵.械呆1)徐例子一鐵立

[c驅(qū)ode:1分:785f泥d修53e3e拴]g(m,摩n)=劇0(m蘇=0,巨n>=干0)獨

=曬g(m-基1,2稠n)+曾n;(m桃>0,案n>=圓0)[/多code:蹈1:785尤fd53e純3e]

細底

a)輪遞歸程序脫暴[code李:1:78乒5fd53購e3e]i倡ntg_駕recur怒sive(旱intm脾,int細n)匆{甘if(m將==0袍&&n堪>=0懂)

詠retur晝n0;爬retur僚n(g_于recur貧se(m占-1,鄙2*n)趁+n);凳明}[/co賞de:1:謙785fd修53e3e錄]壇宿

b)莫非遞歸程序仔冰[code臥:1:78帥5fd53壟e3e]i吳ntg_娘nonre裂cursi冰ve(in旦tm,鬼intn倡)物{向intp奧;雁for(紫p=0土;m>脂0&&摸n>=承0;m鋒--,n支*=2編)

液p+=羽n;疑retur窯np;儉}[/co巖de:1:參785fd剛53e3e競]給

2粉)例子二皆

[c顛ode:1盞:785f展d53e3崗e]f(閃n)=按n+1錫

(n企=0)獎巖伐n*摘f(n/2帶)(n主>0)[罪/code確:1:78噸5fd53左e3e]

壞閑

a諸)遞歸程序朗炸[code番:1:78棚5fd53烘e3e]i腔ntf_班recur鋒sive(茶intn屯)始{皆if(n貢==0儀)

鵲retur蓋n1;刑retur透n(n轉(zhuǎn)*f_r激ecurs恥e(n/2猶));艱}[/co裙de:1:笛785fd卷53e3e拘]鼻

b辰)非遞歸程恩序陪[code燥:1:78皮5fd53掀e3e]i示ntf_孤nonre波cursi侍ve(in第tn)噴{榆intm梁;睬for(突m=1灰;n>聾0;n聚/=2鈴)

滔m*=王n;股retur巨nm++風(fēng);宿}[/co跑de:1:浪785fd抵53e3e楚]

趕旁分析完了伯遞歸程序的槳分類,讓我特們回頭看看尺在向非遞歸兩轉(zhuǎn)換的過程州中用到了什蹤么來實現(xiàn)轉(zhuǎn)態(tài)換:鍛

1)揪循環(huán),因為展程序要在某框個條件下一繪直執(zhí)行下去乎,要代替遞刺歸程序,循三環(huán)必不可少銜,對于尾部傻遞歸,循環(huán)史結(jié)束的伴案條件十分容賢易確定,只友要按照不同躁分支的條件給寫出來就可宴以了.而對桃于非尾部遞滴歸程序,循絮環(huán)結(jié)束的條饅件一況勺般是當(dāng)棧為友空時或者是煌結(jié)束了對遞肯歸調(diào)用樹的近遍歷從樹的愁根結(jié)點退出淘時,而且有迅的時候?qū)懗啥竪hile堅()的形式俗猾博,有時寫成司do..鞋.whil菜e的形式(漿如上面的a菜km函數(shù))料,具體怎樣索,很難說清暈楚,取決于睬你對整個遞眠歸程序的分室析敵濾.重

2)帽遞歸調(diào)用樹練,樹的結(jié)構(gòu)竟在轉(zhuǎn)換的過陰程中是不可強見的,你不悼必為轉(zhuǎn)換專覺門寫一個樹棋結(jié)構(gòu),不過澆能不能把遞崗歸調(diào)用夠瓦中的樹遍歷益方式以及葉駁子結(jié)點,左缸子樹,右子踢樹等元素確槐定好是你能約否正確解決艘問題的關(guān)鍵膜(這一點已牲經(jīng)在敗仔上面的分析者過程中展露列無疑),確營定好這些后域,剩下的工儲作大部分就悲是按照給出給的幾種不同豈的遍歷樹的目方式君灑把程序進行計改寫,這個掀過程就考驗?zāi)懩銓浣Y(jié)構(gòu)匯還有遍歷方眼式是否很好雄的掌握了(戚看出基礎(chǔ)的暈重要了嗎?玩如果棵踏回答是,那善么和我一樣畫好好的打好妥基礎(chǔ)吧,一該切都還不晚諸!!).對任于尾部遞歸菊而言,可以菌看作沒有遞階歸調(diào)用樹,支墓孕所以尾部遞呆歸的難度大忌大降低了.費恨

3)殲棧,非尾部受調(diào)用中需要強棧來保存數(shù)見據(jù),這一點掏已經(jīng)很清楚楚了,需要注螺意幾個問題恥:

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論