2017-07-13 19 views
2

私はそれを視覚化することでJavaの再帰を理解しようとしています。私はユーチューブ上のいくつかのチュートリアルを行っていると、そのうちの一つ再帰を視覚化する方法

public class TestRecursion { 

    public static void main(String []args) { 
     new TestRecursion().reduceByOne(10); 
    } 

    public void reduceByOne(int n) { 
     System.out.println("Before "+n); 
     if(n >= 0) { 
      reduceByOne(n-1); 
      System.out.println("Inside "+n); 
     } 
     System.out.println("After "+n); 
    } 
} 

から、私はこれまで理解しているところでは、以下の例を使用して、reduceByOneへのすべての呼び出しは()実行スタックに置かれることになります。だから、最初のメイン

Stack

のようなものは、()スタックになります。 reduceByOne(10)を呼び出すので、このメソッドはスタックに到達し、次にreduceByOne(9)を呼び出してスタックにプッシュします。 reduceByOne(-1)がスタックにプッシュされた後、実行するメソッドがなくなり、reduceByOne(-1)がポップされて実行されます。

メソッドがポップされると何が起こるのか理解できません。 reduceByOne(2)がスタックからポップされます。私が実行されますコードは、この

public void reduceByOne(2) { 
     System.out.println("Before "+2); 
     if(2 >= 0) { 
      reduceByOne(2-1); 
      System.out.println("Inside "+2); 
     } 
     System.out.println("After "+2); 
    } 

が、これはスタックに再びreduceByOne(2-1)を入れないだろうようになり、信じますか?それともスキップされますか?もしそうなら、ランタイムは何が実行されるのか、メソッドがポップされたら何をスキップするのかをどのように知っていますか?

あまりにも複雑すぎるかもしれません。しかし、私は再帰の明確な理解を得ることができないので、どんな助けも高く評価されます。

+0

* *「私はトラブルの方法がポップされると何が起こるかを理解したのですか?」 - それは、それが呼び出された時点で、以前の方法に戻りますので、ライン 'のSystem.out.printlnを実行します( "Inside" + n); ' - メソッドを呼び出すのではなく、呼び出されたところに戻ります。 – MadProgrammer

+0

ここで理解できるのは、関数呼び出しをスタックに入れる点です。コール全体がスタックに置かれていないと、実行が開始されます。プログラムは、関数が自分自身を呼び出すまで実行され、その後、その呼び出しはスタックに置かれます。したがって、関数が実行されると(スタックの先頭にポップされたもの)、前の項目は、中断した時点から実行を完了します。 –

+1

再帰的メソッドを理解する最善の方法は、小さな問題の解決法(再帰呼び出しによって解決されている)を既に知っていれば、より大きな問題を解決する方法としてそれを表示することです。行方不明の唯一の事は、基本的な場合です(些細な問題を解決する)。 – Henry

答えて

4

n >= 0の場合に最初に実行されるメソッドが返されると、実行は前の "呼び出し"ポイントに戻ります。この場合、実行される次の行はSystem.out.println("Inside "+n);になります。この方法は、その後、終了を進め、前のグリーンが「プッシュ」されているとオレンジの結果となって

Stack And Pop

...例えばコード

にポイントを「コール」に返されます「ポップ」

明らかに、いくつかの点で、あなたはmainに戻りますが、これはこれは「通常」のコードがどのように動作するかよりも異なるものではないだけでイラスト

で、それが戻ったとき、あなたはそれを返し、メソッドを呼び出しますそれは以前に

実行された。これは、プロセスの単純化であるが、私はそれはあなたがより良いプロセス

2

を視覚化することができます願っていた点に、私は、再帰はあなたの例を使用して発生したときに何が起こるかを説明します。 あなたが知っているように、スタックの上にあるメソッドは実行され、ポップアウトされます。この説明は目的を理解するためのものです。

メソッド/メソッドの状態がプッシュされ、スタックからポップされたときの考え方と混同しています。

public static void main(String []args) { 
    new TestRecursion().reduceByOne(10); //first line 
} 

メインメソッドはスタックの先頭に置かれます。

スタック - >main()の最初の行は遭遇として

は今ではreduceByOne(10)を呼び出します。スタックに追加されます。

スタック - reduceByOneとして>reduceByOne(10)()

は(10)、スタックの一番上(メインの実行で)一時停止、およびreduceByOne(10)の実行を開始します。ラインの実行など

reduceByOne(n-1); 

別のメソッド呼び出しが発生し、そのスタックにプッシュ。 reduceByOne(9)がスタックの先頭にあるので、現在のメソッドは実行を一時停止します。

スタック - >reduceByOne(9)reduceByOne(10)()

同様スタックは、メソッドの状態で追加されます。

スタック - >reduceByOne(-1) --- reduceByOne(9)reduceByOneメイン(10)()メソッドの条件が失敗した場合reduceByOne(-1);が、実行される

if(n >= 0) { // now n is -1 
    reduceByOne(n-1); 
    System.out.println("Inside "+n); 
} 

実行を完了すると、reduceByOne(-1)がポップアウトされます。 は今reduceByOne(0)はライン

... 
System.out.println("Inside "+n); // ---- line(1) 
    } 
    System.out.println("After "+n); 
} 

から実行を再開し、飛び出します。今すぐreduceByOne(1)が飛び出してくるので、行(1)からの実行を再開します。今すぐreduceByOne(2)がスタックの上にある場合は、行(1)から実行 を再開します。同様に、それはreduceByOne(10)まで戻ってくる。そして今すぐreduceByOne(10)行(1)からの実行を再開し、ポップアウトされます。現在、mainメソッドだけがスタックに残っています。それも実行され、ポップアウト。こうして実行が終了する。

0

フラクタルを使用して視覚化することができます。あなたはそれを見ることができるように、いくつかの待機点(睡眠)を置くことができます。それは私を一度助けました。すなわち

public class FractalTree extends JFrame { 
public FractalTree() { 
    setLocation(500, 50); 
    setSize(800, 700); 
    setTitle("Fractal Tree"); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    add(new TreePanel()); 
    //add(new MyCanvas()); 
    setVisible(true); 
} 

public static void main(String[] args) { 
    // TODO Auto-generated method stub 

    // initialize screen elements 
    FractalTree ft = new FractalTree(); 

} 

} 


class TreePanel extends JPanel { 
private static int maxLength = 10;; 

public void drawFractalTree(Graphics g, int x1, int y1, double angle, int level) { 
    if (level <= 0) 
     return; 
    // 

    int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * level * maxLength); 
    int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * level * maxLength); 

    // set color 
    setLineColor(g, level); 
    // draw between two points 
    g.drawLine(x1, y1, x2, y2); 


    try { 
     TimeUnit.SECONDS.sleep(1); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


    // call rec. 
    drawFractalTree(g, x2, y2, angle - 20, level - 1); 
    drawFractalTree(g, x2, y2, angle, level - 1); 
    drawFractalTree(g, x2, y2, angle + 20, level - 1); 

} 

@Override 
public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    g.setColor(Color.WHITE); 
    g.fillRect(0, 0, 800, 700); 
    drawFractalTree(g, 400, 500, -90, 9); 
} 

public void setLineColor(Graphics g, int i) { 
    switch (i) { 

    case 1: 
     g.setColor(Color.GREEN); 
     break; 
    case 2: 
     g.setColor(Color.YELLOW); 
     break; 
    case 3: 
     g.setColor(Color.ORANGE); 
     break; 
    case 4: 
     g.setColor(Color.CYAN); 
     break; 
    case 5: 
     g.setColor(Color.MAGENTA); 
     break; 
    case 6: 
     g.setColor(Color.PINK); 
     break; 
    case 7: 
     g.setColor(Color.RED); 
     break; 
    case 8: 
     g.setColor(Color.BLUE); 
     break; 
    case 9: 
     g.setColor(Color.GRAY); 
     break; 
    default: 
     g.setColor(Color.BLACK); 
     break; 
    } 
} 
} 
関連する問題