2011-07-30 3 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

ヒントありがとうございますが、まだプログラミングを始めています。私は間もなくそれをすぐに学ぶでしょう – Raven

+0

@Deanie - [編集権限](http://stackoverflow.com/help/privileges/edit)をお読みください。ページ、特に「小さな、些細な編集はお勧めできません。あなたが観察したすべての問題を修正して、投稿を著しく改善しようとしています。特に、2,000人の議員がいるまでは、それぞれの編集(些細なタグのみの編集でさえ)は最大5人の他のユーザーからの投票が必要です。編集回数をカウントしてください。 –

答えて

5

再帰は最初に把握するのが少し難しいかもしれません。ベースケースこれは、再帰関数でなく、がもう自分自身を呼び出すための条件であり、もう1つの部分( "else ")、関数が呼び出され続けます。 "rings == 1"の条件が基本ケースです。

関数 "move_rings"は毎回小さい引数で呼び出されます。後続の各呼び出しで、 "rings == 1"が真になるまで、変数 "rings"は小さくなり(したがって、基底のケースに近づく)、関数は自身を呼び出すことを停止します。

希望に役立ちます。

+0

ありがとうございました他のすべての答えについても)...私はそれをちょっと把握することができました。ベースケース(またはif条件)が1に達すると、それは.. – Raven

+0

..今、私の頭に別の問題が発生します...最後の再帰的な動きはどのように機能しますか? ( "move_rings(rings_1、other、destination、source);"部分)...リングは今では1に等しいので、リング-1の引数はゼロに等しいでしょうか? (私の歯はこれらの再帰のものでクリンチされます) – Raven

+0

"move_rings"の最初の再帰呼び出しが終了すると、 "rings"の値は、その呼び出しが開始されたときのものと同じになります。再帰呼び出しで使用される「リング」のバージョンは、実際には「ローカル」バージョンであり、メインの「move_rings」コールの「リング」の値には影響しません。そのローカルバージョンが1に等しい場合、再帰呼び出しの最初のセットは終了しますが、メインの「move_rings」関数は古い値の「rings」で続行されます。 Anders Abelの答えは、これについて考えることに関連しています。 –

0

たびに関数再帰、それが最終的に1ずつ減少リング・カウントを取得し、すべての枝がrings==1状態に達すると終了します。これは、else状態の枝とif状態の枝を持つ2分木として想像することができます。

1

move_ringsを呼び出すたびに、パラメータrings - 1が渡されるためです。最後に、渡されたパラメータは1となり、rings == 1は真となります。

再帰的(または任意の種類のリエントラント)関数を扱う場合、ローカル変数の仕組みを理解することが重要です。関数を呼び出すたびに、ローカル変数とパラメータを独自にインカネーションします。煉瓦のスタック(ハノイの塔にある杭のようなもの)を想像してください。各ブリックには関数パラメータが含まれています。関数が呼び出されると、最上位のレンガの値を使用して、その関数のパラメータがスタックの最上部に配置され、関数が実行されます。関数が戻ると、一番上のレンガは破棄され、下のレンガの値に戻ります。

+0

これは非常に役に立ちます。最初は再帰関数を視覚化するときに "ローカル変数化"の部分を見逃してしまったと思います...しかし、今はもっとわかりやすいです...ありがとうございます – Raven

0

elseブランチでは、rings - 1でコールが行われます。あなたがそれを増やさないので、最終的にrings1となり、ifブランチがヒットします。この分岐で再帰が発生しないので、このメソッドは終了します。

3

​​が呼び出されるたびに、最初の引数が小さくなるためです。最終的に、無限の数のリングを仮定すると、関数は1つのリングでのみ呼び出されます。これは再帰を返す終了条件です。

これはバイナリツリー構造のようです。無限の数のノードを仮定すると、最終的にそれ以上ノードが存在しない葉ノードに到達します。次に、リーフノードを見つけた他のコードパスと共に、スタックのトラバースを開始することができます。

0

move_rings関数を呼び出すたびに、リング数が1減らされます。最終的には、リング数は1になります。 しかし、このコードは、うまく書かれていないため、無限ループを生成する可能性があります。リングの数が1より大きくなることはありません。したがって、メイン関数に入力された呼び出し回数が1未満の場合、再帰を停止する条件には決して達しません。

0

move_ringsmove_ringsを呼び出すと、関数の2番目の呼び出しが完全に新しく開始します。それは完全に別々の変数セットを持っています。他の機能と同じようにmove_ringsと呼ばれます。それはちょうど同じ名前を持ち、同じロジックを含む "別の関数"と呼ばれることがあります。

関数の2回目の呼び出しでは、最初の呼び出しがそのパラメーターの値よりも小さい値を渡したため、ringsの値は低くなります。最終的には、これらの再帰呼び出しの1つで、値は1になり、関数の先頭にあるifテストは真となります。これにより、さらに再帰が回避され、その関数が戻ります。直前の関数の呼び出しは、まるでほかの関数を呼び出したかのように、元の場所から再開します。それは印刷を行い、同様のことが起きた後、再帰呼び出しを行い、完了します。そして、すべての方法で "バックアップ"。

関連する問題