This is a step by step trace of the example presented at Tracing recursive methods.

The same trace is available with each step on its own page, starting with Step 1.

Step 1: initial call

public int mystery(int b)
{
    if (b == 0)
        return 0;
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
}

Call stack

m(5)

Explanation

Since mystery has more than one call to itself, the calls are labeled. It doesn’t matter which call is labeled call 1 and which is labeled call 2, as long as the usage is consistent.

The initial call to mystery(5) is added to the stack, abbreviated as m(5).

Step 2: mystery(5)

public int mystery(int b)
{
    if (b == 0)                    // checks if 5 == 0, which is false
        return 0;
    
    if (b % 2 == 0)                // checks if 5 is even, which is false
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
                                   // stops at call 2 and calls m(4)
}

Call stack

m(4)
m(5)2

Explanation

The comments in the code above show the trace through m(5).

The statement if (b % 2 == 0) when b is 5 could be traced as: checks if 5 % 2, which is 1, is equal to 0, which is false. Since the statement is obviously checking if b is even, it could also be traced as: checks if 5 is even, which is false.

The 2 next to m(5) in the call stack indicates that m(5) stopped at call 2. This will become important when control is later returned to m(5).

The new call to m(4) is added to the top of the call stack. m(5) is suspended waiting for m(4) to return.

The + 2 is ignored because it has not yet been executed.

In the statement return mystery(b - 1) + 2;, return is the last command that executes. Everything to the right of return executes first. The return command in m(5) has not yet executed.

Step 3: mystery(4)

public int mystery(int b)
{
    if (b == 0)                    // checks if 4 == 0, which is false
        return 0;
    
    if (b % 2 == 0)                // checks if 4 is even, which is true
        return mystery(b - 1) + 3; // call 1
                                   // stops at call 1 and calls m(3)
    else
        return mystery(b - 1) + 2; // call 2
}

Call stack

m(3)
m(4)1
m(5)2

Explanation

The new call to m(3) is added to the top of the stack. m(4) is suspended waiting for m(3) to return. m(5) remains suspended waiting for m(4) to return. Only the topmost call on the stack that has not yet returned is active.

Step 4: mystery(3)

public int mystery(int b)
{
    if (b == 0)                    // checks if 3 == 0, which is false
        return 0;
    
    if (b % 2 == 0)                // checks if 3 is even, which is false
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
                                   // stops at call 2 and calls m(2)
}

Call stack

m(2)
m(3)2
m(4)1
m(5)2

Step 5: mystery(2)

public int mystery(int b)
{
    if (b == 0)                    // checks if 2 == 0, which is false
        return 0;
    
    if (b % 2 == 0)                // checks if 2 is even, which is true
        return mystery(b - 1) + 3; // call 1
                                   // stops at call 1 and calls m(1)
    else
        return mystery(b - 1) + 2; // call 2
}

Call stack

m(1)
m(2)1
m(3)2
m(4)1
m(5)2

Step 6: mystery(1)

public int mystery(int b)
{
    if (b == 0)                    // checks if 1 == 0, which is false
        return 0;
    
    if (b % 2 == 0)                // checks if 1 is even, which is false
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
                                   // stops at call 2 and calls m(0)
}

Call stack

m(0)
m(1)2
m(2)1
m(3)2
m(4)1
m(5)2

Step 7: mystery(0)

public int mystery(int b)
{
    if (b == 0)                    // checks if 0 == 0, which is true
        return 0;                  // stops and returns 0
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
}

Call stack

m(0)   returns 0
m(1)2
m(2)1
m(3)2
m(4)1
m(5)2

Explanation

m(0) stops and returns 0. returns is added to the call stack next to m(0) to indicate that the method call has returned (ended). In this case, m(0) returns a value, so 0 is added after returns.

In a real call stack, m(0) would be removed. m(0) is left on this stack since it is difficult to remove on paper and the return value is needed for future reference.

Step 8: Back in mystery(1)

public int mystery(int b)
{
    if (b == 0)
        return 0;
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
                                   // finished call 2, got back 0
                                   // adds 2
                                   // stops and returns 2
}

Call stack

m(0)   returns 0
m(1)   returns 2
m(2)1
m(3)2
m(4)1
m(5)2

Explanation

After m(0) returns, control returns to the topmost method on the stack that has not yet returned, which is m(1).

The stack (in the previous step) shows a 2 next to m(1), so call 2 just finished. call 2 returned 0. When a method returns a value, the return value is used in place of the method call.

The statement return mystery(b - 1) + 2;
becomes return 0 + 2;

Step 9: Back in mystery(2)

public int mystery(int b)
{
    if (b == 0)
        return 0;
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
                                   // finished call 1, got back 2
                                   // adds 3
                                   // stops and returns 5
    else
        return mystery(b - 1) + 2; // call 2
}

Call stack

m(0)   returns 0
m(1)   returns 2
m(2)   returns 5
m(3)2
m(4)1
m(5)2

Step 10: Back in mystery(3)

public int mystery(int b)
{
    if (b == 0)
        return 0;
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
                                   // finished call 2, got back 5
                                   // adds 2
                                   // stops and returns 7
}

Call stack

m(0)   returns 0
m(1)   returns 2
m(2)   returns 5
m(3)   returns 7
m(4)1
m(5)2

Step 11: Back in mystery(4)

public int mystery(int b)
{
    if (b == 0)
        return 0;
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
                                   // finished call 1, got back 7
                                   // adds 3
                                   // stops and returns 10
    else
        return mystery(b - 1) + 2; // call 2
}

Call stack

m(0)   returns 0
m(1)   returns 2
m(2)   returns 5
m(3)   returns 7
m(4)   returns 10
m(5)2

Step 12: Back in mystery(5)

public int mystery(int b)
{
    if (b == 0)
        return 0;
    
    if (b % 2 == 0)
        return mystery(b - 1) + 3; // call 1
    else
        return mystery(b - 1) + 2; // call 2
                                   // finished call 2, got back 10
                                   // adds 2
                                   // stops and returns 12
}

Call stack

m(0)   returns 0
m(1)   returns 2
m(2)   returns 5
m(3)   returns 7
m(4)   returns 10
m(5)   returns 12

Explanation

m(5) is the original call. m(5) returns 12.

Review recursive method tracing with AP CS Tutor Brandon Horn.

Additional recursion resources

Comments

Comment on Tracing recursive methods