2011-07-30 113 views
4

我知道遞歸是一種在函數本身內調用函數的技術。 但下面的代碼混淆了我它是如何能在第一遞歸之後做cout部分:函數如何在遞歸之後執行一個動作?

(此代碼解決了河內難題塔)

#include <iostream> 
using namespace std; 

void move_rings(int n, int src, int dest, int other); 

int main(void) 
{ 
    int rings;      
    cout << "Number of Rings: "; 
    cin >> rings; 
    move_rings(rings, 1, 3, 2); 

    system("PAUSE"); 
} 

void move_rings(int rings, int source, int destination, int other) 
{ 
    if (rings == 1) 
    { 
     cout << "Move from " << source << " to " << destination << endl; 
    } 
    else  
    { 
     move_rings(rings - 1, source, other, destination); 
     cout << "Move from " << source << " to " << destination << endl; 
     move_rings(rings - 1, other, destination, source); 
    } 
} 

正如你所看到的,在功能move_ringsif聲明後自行調用。

當我想象這一點,我看到永無止境的循環......這怎麼可能對這個功能做

cout << "Move from " << source << " to " << destination << endl; 

一部分?

程序的輸出是這樣的:

Move from 1 to 3 
Move from 1 to 2 
Move from 3 to 2 
Move from 1 to 3 
Move from 2 to 1 
Move from 2 to 3 
Move from 1 to 3 
+1

您是否使用了一些IDE(例如Eclipse)?如果是這樣,您可以使用調試器逐步完成程序,以更好地瞭解發生了什麼。學習如何使用調試器是一項基本技能,所以現在就開始吧。 –

+0

謝謝你的提示,但我還是開始了編程though..I'll肯定很快 – Raven

+0

研究它@Deanie - 請閱讀[編輯權限](http://stackoverflow.com/help/privileges/edit)尤其是關於「微小的,微不足道的修改令人沮喪的部分 - 嘗試在編輯時讓帖子顯着更好,糾正您觀察到的所有問題。」特別是,請記住,除非您有2,000位代表,否則每次編輯(甚至是微不足道的,僅用於標記的編輯)都需要最多5位其他用戶的投票。請進行編輯。 –

回答

5

遞歸首先可能有點難以掌握。據「點擊」對我來說,當我想過這個問題是這樣的:你有一個基本情況,這是這將導致遞歸函數本身了電話的條件,然後你有另一部分(「其他「在你的代碼中),函數將繼續被調用。 「戒指== 1」條件是您的基本情況。

功能「move_rings」被調用,每次一個較小的論點。在隨後的每次調用中,變量「rings」變小(因此「移近」基本情況),直到「rings == 1」爲真,然後該函數停止調用它自己。

希望有所幫助。

+0

非常感謝你的回答(以及所有其他答案)...我能夠掌握一點它,現在我知道,當基本情況(或if條件)達到1時,它會打印出來.. – Raven

+0

..現在,另一個問題出現在我的頭上......最後一個遞歸移動是如何工作的? (「move_rings(rings - 1,other,destination,source);」part)...既然環現在等於1,那麼ring-1的參數是否等於零?從而成爲一個無限循環?.. .. AARGH(我的牙齒被敲定與這些遞歸東西) – Raven

+0

一旦「move_rings」終止,「環」的價值將是不管它是什麼時調用啓動了第一次循環調。遞歸調用中使用的「鈴聲」版本實際上是一個「本地」版本,不會影響主「move_rings」調用中「鈴聲」的值。當本地版本等於1時,第一組遞歸調用結束,但主「move_rings」函數繼續使用舊值「ring」。 Anders Abel的回答與思考這個問題有關。 – 2011-07-30 14:51:22

0

每一次函數遞歸中,它被一個振鈴次數減1。最後,所有分支機構達到rings==1狀態,終止。您可以將其想象爲一個二叉樹,其分支處於else狀態,其葉子處於if狀態。

1

因爲在每次調用move_rings時它都會傳遞參數rings - 1。最後,傳遞的參數將爲1rings == 1將爲true。

在處理遞歸(或任何類型的可重入)函數時,瞭解局部變量的工作方式非常重要。每個函數的調用都有自己的本地變量和參數。設想一堆磚(如河內塔中的一堆)。每個磚塊都包含功能參數。當一個函數被調用時,這個函數的參數被放置在堆棧的頂部,函數被執行,使用最頂層的磚的值。當函數返回時,最上面的磚被丟棄,返回到下面磚的值。

+0

這是非常有幫助的,我想在可視化第一遞歸函數時,我錯過了「局部變量的化身」的一部分......但現在,它更清晰的給我...謝謝你這麼多 – Raven

0

else分支中,通話使用rings - 1完成。由於你永遠不會增加它,最終rings將是1if分支將被擊中。由於在這個分支中沒有發生遞歸,所以該方法終止。

3

因爲每調用一次​​,它的第一個參數就會變小。最終,假設一個非無限數目的環,該功能將僅在一個環上被調用。這是導致遞歸返回的終止條件。

將其描繪爲一棵二叉樹結構。假設節點數量不是無限的,你最終會到達一個葉節點,超過這個節點就沒有了。然後,您可以開始遍歷堆棧以及找到葉節點的其他代碼路徑。

0

每次調用move_rings函數時,環數都減1。最終,戒指的數量將是1. 然而,這段代碼確實會產生無限循環,因爲它的寫法不好。從不檢查環的數量是否大於1.因此,如果在主函數中輸入的環數小於1,永不會達到停止遞歸的條件。

0

move_rings調用move_rings,函數的第二個電話開始完全新鮮的。它有一組完全獨立的變量。就好像move_rings調用了其他任何函數。它恰好在調用具有相同名稱幷包含相同邏輯的「另一個函數」。

在函數的第二次調用中,rings將具有較低的值,因爲第一次調用爲該參數傳遞的值比它自己小。最終,在這些遞歸調用中的一個上,值將達到1,並且在函數開頭的if測試將測試爲真。這避免了進一步的遞歸,並且該函數返回。該函數的前一個調用然後從它原來的位置恢復,就像調用了其他函數一樣。它完成它的打印,然後在發生類似事件時進行另一次遞歸調用,然後完成。等一路「備份」。

相關問題