【算法基礎】遞歸的世界你不懂……

                           

轉眼間又到了深夜,終於能好好吃一把雞了。算法



…………微信

等等,TM11點就停電了。玩雞毛!!!網絡

哦……那麼,就只能……學習了……函數

今天學啥呢?學習

對,沒錯優化

今天要教給你們的是spa

遞(zhuang)歸(bi)大法.net







本節綱要:3d

-     什麼是遞歸orm

-     遞歸函數的工做原理

-     經典的遞歸問題

-     遞歸的一些適用狀況

 

什麼是遞歸?

 

在此以前,讓老衲來引用一句名言:

 


迭代的是人,遞歸的是神  

–L. Peter Deutsch

那麼,何爲遞歸呢?別急,聽老衲慢慢爲施主道來。


所謂遞歸(recursion):

說白了就是子程序(或函數)直接調用本身間接調用本身的一種基本方法。運用遞歸一般能夠把一個大型複雜的問題層層轉化爲一個與原問題類似的規模較小的問題來求解,從而減小程序的代碼量。

 

遞歸調用的形式:

-直接調用:即在函數中調用函數自己

舉個栗子,下面一段代碼用於求斐波那契數列的第N項:


- 間接調用:指A函數執行中調用了B函數,而B函數又調用了A函數。

仍是再舉個栗子吧。

固然,這是一個死遞歸,沒有出頭之日的。

簡單介紹了遞歸,下面開始咱們的重頭戲。


遞歸的工做原理:

-      先談談遞歸函數的內部執行過程:

  1. 開始時,系統先爲遞歸調用設立一個工做棧,它的結構包括值參、局部變量和返回地址。

  2. 每次執行遞歸調用時,系統會把遞歸函數的值參和局部變量的當前值以及調用後的返回地址壓棧。

  3. 每次遞歸調用結束後,將棧頂元素出棧,而後轉向返回地址指定的位置繼續執行。

 

這裏關於棧的內容暫時不過多贅述,你們能夠自行上網找資料查詢。其實說白了遞歸調用的本質仍是函數調用,那函數調用必然會遵循一個原則:被調用的函數會複製一個副本,爲調用者服務,而不受其餘函數的影響。


不少人把遞歸理解爲一種代碼反覆循環使用。其實這是有失偏頗的。像前面說的,一個函數func被調一次,他就在內存中複製一份代碼,再調用,再複製。而後根據內存的棧式管理返回退出。你也能夠把被遞歸調用各個函數看成不一樣名的函數,這樣更便於理解。

 

-      下面來結合一個求階乘的例子來討論一下這個過程:

先假設咱們在main函數裏面傳入的num=3吧。

1.一層執行到res=3*factorial(3-1);中止,執行二層factorial (3-1),也就是factorial (2)


2.二層執行到res=2*factorial(2-1);中止,執行三層factorial (2-1),也就是factorial (1)


3.三層執行到if(num==1) res=1;而後return(res)到二層的factorial (2-1)的位置,二   層繼續執行


4.二層執行res=1*2;而後就return(res)到一層factorial (3-1)的位置,一層繼續執行


5.一層執行res=2*3;而後就return(res)到了最初調用factorial (3)的main函數裏。因此就獲得結果爲6


整個過程大致就是這樣的。


函數的執行流程:


 


遞歸的經典問題

 

漢諾塔(Hanoi Tower),又稱河內塔,源於印度一個古老傳說。大梵天創造世界的時候作了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序從新擺放在另外一根柱子上。而且規定,任什麼時候候,在小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動一個圓盤。問應該如何操做?

 

在學習了上面的遞歸原理以後,這裏是否是想動手AC一下這道題呢?

假若有ABC三根柱子,先假設A柱子只有3個盤子的狀況。盤子從上到下依次編號爲123.咱們能夠先把1和2號盤子藉助C柱子,移動到B柱子上,而後在將3號盤子移動到C柱子上。而後再借助A柱子,將1和2號盤子移動到C柱子上,done!至於怎麼把1和2號盤子藉助C移到B柱子上,想必也不用多說。


那麼,假若有N個盤子,咱們只須要藉助C柱子,將1到N-1號盤子移動到B柱子上,再將N號盤子移動到C上,再將1到N-1號盤子移動到C上,done!而藉助C柱子移動1到N-1號盤子到B柱子,又只須要考慮將1到N-2號盤子藉助B移到C上,最後再從C裏移動回來。這樣咱們就不斷將問題縮小了。臥槽是否是有點暈,那就對了。


 

算法描述:

A柱子只有一個盤子的時候,只須要從將A柱子上的一個盤子移到C塔上。

-   當A柱子上有兩個盤子是,先將A柱子上的1號盤子(編號從上到下)移動到B柱子上,再將A柱子上的2號盤子移動的C柱子上,最後將B柱子上的小盤子移動到C柱子上。

-  當A柱子上有3個盤子時,先將A柱子上編號1至2的盤子(共2個)移動到B柱子上(需藉助C柱子),而後將A柱子上的3號最大的盤子移動到C柱子,最後將B柱子上的兩個盤子藉助A塔移動到C柱子上。

-  當A柱子上有n個盤子是,先將A柱子上編號1至n-1的盤子(共n-1個)移動到B柱子上(藉助C柱子),而後將A柱子上最大的n號盤子移動到C柱子上,最後將B柱子上的n-1個盤子藉助A柱子移動到C柱子上。

綜上所述,除了只有一個盤子時不須要藉助其餘柱子外,其他狀況均同樣

 

好,又到了激動銀心的看代碼時間:

 

關於遞歸的適用狀況:   

遞歸一般用來解決結構自類似的問題。所謂結構自類似,就是說在結構上組成類似的,能夠採用同一種方法去解決。具體地,整個問題的解決,能夠分爲兩部分:第一部分是一些特殊狀況,有直接的解法;第二部分與原問題類似,但比原問題的規模小實際上,遞歸就是分而治之的思想,把大問題化爲小問題,再把小問題化爲更小的問題,在解決這樣一個個的小問題以後,大問題天然迎刃而解。

所以,遞歸有兩個基本要素: 

1)邊界條件:肯定遞歸到什麼時候終止,也稱爲遞歸出口。  

2)遞歸模式:大問題是如何分解爲小問題的,也稱爲遞歸體。遞歸函數只有具有了這兩個要素,才能在有限次計算後得出結果。



-The  End-


編輯 / 鄧發珩

指導老師 / 秦時明嶽





注:部分資料來源網絡。做者爲優化突擊隊成員,

若有疑問,歡迎諮詢:鄧發珩 (華中科技大學本科一年級、聯繫方式:2638512393@qq.com、我的公衆號:程序猿聲)秦虎老師(professor.qin@qq.com)



本文分享自微信公衆號 - 程序猿聲(ProgramDream)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索