如何可视化递归

时间:2017-07-13 04:56:23

标签: java recursion

我试图通过可视化来理解Java中的递归。我已经在youtube上学习了一些教程并使用下面的一个示例

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

所以,首先main()进入堆栈。因为它调用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)放到堆栈上吗?还是会被跳过?如果是这样,运行时如何知道执行什么以及在弹出方法后要跳过什么?

可能是我太复杂了。但是,我无法清楚地了解递归,因此非常感谢任何帮助。

3 个答案:

答案 0 :(得分:5)

当方法返回时(在你的情况下将首先发生n >= 0),执行将返回到前一个"调用"在这种情况下,要执行的下一行将是System.out.println("Inside "+n);,之后每个方法将继续退出并返回到先前的" call"在代码中指出

例如......

Stack And Pop

绿色是"推动"而橙色是" pop"

的结果

显然,在某些时候,你会回到main,但这只是一个例子

这与"正常"没有什么不同。代码工作,你调用一个方法,当它返回时,它返回到之前执行的点

这是对过程的过度简化,但我希望它能让您更好地可视化过程

答案 1 :(得分:2)

I will explain what happens when the recursion occurs using your example. As you know the method which is on top of the stack gets executed and get popped out. This explanation is just for understanding purpose.

You have confused with the idea when method/method state is pushed and popped from the stack.

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

Main method get on top of the stack.

Stack -> main()

Now as the first line encounters it calls reduceByOne(10). So that gets added to the stack.

Stack -> reduceByOne(10) main()

As reduceByOne(10) is on top of the stack,execution of main() pauses, and execution of reduceByOne(10) starts. As the execution of line

reduceByOne(n-1);

Another method call occurs and its pushed to stack. So current method pauses execution because reduceByOne(9) is now on top of stack.

Stack -> reduceByOne(9) reduceByOne(10) main()

Similarly stacks gets added with method states.

Stack -> reduceByOne(-1) --- reduceByOne(9) reduceByOne(10) main()

When reduceByOne(-1); is executed, if condition in the method fails.

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

And it completes the execution, reduceByOne(-1) gets popped out. Now reduceByOne(0) resumes execution from the line

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

and gets popped out. Now reduceByOne(1) resumes execution from line(1) as gets popped out. Now reduceByOne(2) is on top of the stack, it resumes its execution from line(1). Similarly it comes back upto reduceByOne(10). And now reduceByOne(10) completes execution resuming from line(1) and gets popped out. Now only main method remains in the stack. It also gets executed and popped out. Thus execution terminates.

答案 2 :(得分: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;
    }
}
}