遞歸工作原理

遞歸(recursion)就是子程序(或函數)直接調用自己或通過一系列調用語句間接調用自己,是一種描述問題和解決問題的基本方法。
 
    遞歸通常用來解決結構自相似的問題。所謂結構自相似,是指構成原問題的子問題與原問題在結構上相似,可以用類似的方法解決。具體地,整個問題的解決,可以分爲兩部分:第一部分是一些特殊情況,有直接的解法;第二部分與原問題相似,但比原問題的規模小。實際上,遞歸是把一個不能或不好解決的大問題轉化爲一個或幾個小問題,再把這些小問題進一步分解成更小的問題,直至每個小問題都可以直接解決。因此,遞歸有兩個基本要素:
 
    (1)邊界條件:確定遞歸到何時終止,也稱爲遞歸出口。
 
    (2)遞歸模式:大問題是如何分解爲小問題的,也稱爲遞歸體。遞歸函數只有具備了這兩個要素,才能在有限次計算後得出結果
 
在遞歸函數中,調用函數和被調用函數是同一個函數,需要注意的是遞歸函數的調用層次,如果把調用遞歸函數的主函數稱爲第0層,進入函數後,首次遞歸調用自身稱爲第1層調用;從第i層遞歸調用自身稱爲第i+1層。反之,退出第i+1層調用應該返回第i層。
 
 
遞歸函數的內部執行過程
 
    一個遞歸函數的調用過程類似於多個函數的嵌套的調用,只不過調用函數和被調用函數是同一個函數。爲了保證遞歸函數的正確執行,系統需設立一個工作棧。具體地說,遞歸調用的內部執行過程如下:
 
    (1)運動開始時,首先爲遞歸調用建立一個工作棧,其結構包括值參、局部變量和返回地址;
 
    (2)每次執行遞歸調用之前,把遞歸函數的值參和局部變量的當前值以及調用後的返回地址壓棧;
 
    (3)每次遞歸調用結束後,將棧頂元素出棧,使相應的值參和局部變量恢復爲調用前的值,然後轉向返回地址指定的位置繼續執行。 

 

 

以階乘爲例說明遞歸的工作原理:

long ff(int n) { long f; if(n<0)

printf("n<0,input error"); else if(n==0||n==1)

f=1; //爲什麼f=1,就不再繼續遞歸調用?

else

f=ff(n-1)*n;//這一步到底是怎麼工作的? return(f); }

 

首先要清楚,遞歸就是某個函數直接或間接地調用了自身,這種調用方式叫做遞歸調用。說白了,還是函數調用。既然是函數調用,那麼就有一個雷打不動的原則:所有被調用的函數都將創建一個副本,各自爲調用者服務,而不受其他函數的影響。

你的ff函數,遞歸多少次,就有多少個副本,再利用內存的棧式管理,反向退出。這個最好找一下“棧”這方面的東西看看,挺容易的,就像子彈匣一樣,先進後出。

你不理解,很有可能是因爲誤以爲該這幾行代碼被反覆使用了。從某種意義上說,這是不對的,因爲就像剛纔說的,一旦被調用,他將在內存中複製出一份代碼,再被調用就再複製一份,換句話說,你可以吧同一個函數的多次調用理解稱謂多個不同函數的一次調用,這樣也會會簡單些。

再說=1和=0是爲什麼退出。遞歸,很需要注意的就是死遞歸,也就是說,某一個函數進入了無限調用自身的情況,永無止境地消耗內存等資源,這在編程方面是一大忌。但凡是遞歸的函數,一定會在某一個地方存在能夠返回上一層函數的代碼,否則必定死遞歸。ff函數中,那個else就是返回的出口,你可以這樣想,如果沒有那個if來進行判斷,你遞歸到什麼時候算完?ff是不是會一直調用自己呢?別指望被調用的函數會自動結束,因爲一旦某個函數A中調用了函數B(或者自己),那麼A中的代碼會停在調用的位置,而轉向B中去執行,同理,如果B又調用函數C,那麼B又停在調用的位置,去執行C,如果無限調用,那麼程序是永遠不會結束的。當然,也有這種情況,A調用B,然後繼續自己的代碼,不管B的死活,這種不在我們的討論範圍內,因爲那牽扯到另一種編程方式:多線程。(我們現在說的是單線程

給你拆極不看看吧:

求3!=?

一層執行到f=ff(3-1)*3;停止,執行二層ff(3-1),也就是ff(2)

二層執行到f=ff(2-1)*2;停止,執行三層ff(2-1),也就是f(1)

三層執行到else if(n==0||n==1) f=1;然後return(f)到二層的ff(2-1)的位置,二層繼續執行

二層執行f=1*2; 然後就return(f)到一層ff(3-1)的位置,一層繼續執行

一層執行f=2*3; 然後就return(f)到了最初調用ff(3)的main函數裏,所以就得到y=6

大體過程就是這樣的

這裏每次一層都相當於一個不同的函數,你可以給他們起名爲ff1,ff2,ff3.....這樣就不混了。只要注意一點,調用一次,不是在代碼本身上執行,而是會複製出一份在執行,雖然不太恰當,但足以說明問題。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章