0% found this document useful (0 votes)
5 views23 pages

14a Recursion

Uploaded by

Dr. Platinum
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views23 pages

14a Recursion

Uploaded by

Dr. Platinum
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 23

Recursion

A method that calls itself (see above)


What is recursion?

Recursion is, put simply, the process of a method


calling itself. It is a problem solving technique.

Why would we need to do that, you ask? Recursion


helps us break up complex problems into smaller and
smaller problems, until we reach a problem so simple
that we can solve it immediately.

Some extremely challenging problems can be solved


very elegantly with recursion.
Recursive example
Suppose you are trying to count the number of ears on n
number of bunnies*.

Let's assume that calculating the number of ears on more


than one bunny is too complex – how could we break up
the problem into smaller and smaller pieces, until the
problem is simple enough to solve?

Essentially, only the simplest possible case is solvable –


in this example, for only 1 bunny. We know that 1 bunny
has 2 ears. This is referred to as our base case.
* Credit goes to codingbat.com for this perfect beginning recursion example
Base case explanation

In our example, the base case – a problem so simple


that we can solve it immediately – is when there is only
one bunny. With one bunny, we return a value (2)
immediately.

Everything else but the base case is “too complex” to


solve and must be broken up into smaller problems.

Only when we reach our base (simplest) case can we


immediately solve the problem.
Break the problem into smaller pieces

If there is any more than one bunny, it's simply too


complex to calculate the number of ears! Let's attempt
the break the problem up into smaller pieces.

However, keep in mind that we know one bunny has


two ears.

To solve this problem recursively, you would return 2


(to account for one bunny), then check again with one
less bunny, until there is only one bunny remaining.
Recursive code
public int numEars(int bunnies)
{
if (bunnies == 1) { //base case reached
return 2; //solve immediately
}

else { //too complex! Break it up


return 2 + numEars(bunnies – 1);
}
}

You know that, if the base case hasn't been reached, there is more
than 1 bunny. Hence, return 2 (because you know 1 bunny has 2
ears), plus another call to the method with one less bunny.
Explanation of recursive code
In our example, if our base case is reached – if the bunnies
parameter is 1 – we immediately return 2. Otherwise, we
(recursively) call the method again, returning the value of 2
plus whatever the method with the bunnies parameter
decremented by 1 returns.

Why do we decrement the bunnies parameter by 1? If we


didn't, we would recursively call forever, because our recursive
method calls don't converge on our base case.

Hence, the base case is the termination point of the method.


Once we reach the base case, the problem is so simple, we
solve it (return an actual value, not a method call).
Explanation (cont'd)
Once the base case is reached, a value is returned – no more
recursive method calls take place.

Once an actual value is returned, it returns back to where that


method call took place – in other words, inside another copy of the
method.

The call sequence looks like this, for numEars(4):

numEars(4) = 2 + numEars(3), where


numEars(3) = 2 + numEars(2), where
numEars(2) = 2 + numEars(1), where
numEars(1) = 2

<stunned silence>
Explanation (cont'd)
For a method call numEars(4):

numEars(4) = 2 + numEars(3), where


numEars(3) = 2 + numEars(2), where
numEars(2) = 2 + numEars(1), where
numEars(1) = 2 //base case

The values are returned "back up the chain" of method calls, so

numEars(2) = 2 + numEars(1), but we solved numEars(1)!

We can now replace this method call with a real value.

numEars(2) = 2 + 2 //now THIS one has been solved

numEars(3) = 2 + numEars(2), which we now know is 4


Factorial example
Many teachers will use factorial as a first recursion example, and for
good reason – it's an inherently recursive thing.

The factorial of 5 is the product (multiplication) of all the numbers from


5 to 1: 5! = 5 * 4 * 3 * 2 * 1

You could of course easily calculate the above using loops! However,
this can also be done in a fairly intuitive way using recursion:

public int factorial(int n)


{
if (n == 1) //base case, 1! is 1
return 1;
else
return n * factorial(n – 1);
}
Factorial example (cont'd)
Let's take a look at what's happening:

• Is the base case reached? If so, great! Return a value of 1.

• Otherwise, try to break the problem up into smaller pieces.

• Return the current value of n multiplied by another recursive method


call, with the parameter decremented by one.

In the end, the method calls for factorial look like the following:

return 5 * factorial(4);
return 5 * (4 * factorial(3));
return 5 * (4 * (3 * factorial(2)));
return 5 * (4 * (3 * (2 * factorial(1))));
return 5 * (4 * (3 * (2 * (1))));

The last method call (the base case) doesn't return another method call, it returns a
value, which returns values to previous calls.
Factorial example (cont'd)
Recursion works in a "top down" manner, until the base case is reached.
Upon reaching the base case, recursive calls "unravel" back up the chain:
Tracing recursive method calls
What does the following code return when mystery(5) is called?

public int mystery(int n)


{
if (n == 3)
return 2;

else
return 1 + mystery(n – 1);
}
Method calls go on a stack
When a program calls multiple methods, a data structure
called a stack is used to remember them; think of stacking
lunch trays up in the cafeteria.

The initial call is mystery(5) (for the sake of expediency


let's shorten the method name to m), or m(5).

The parameter n does not equal 3, therefore our base case


has not been reached. The method is called again
(recursion!), with the parameter decremented by one.

The next recursive method call m(4) stacks on top of the


previous method that called it (m(5)). This continues until
there are no more calls (when we reach the base case).
Method calls go on a stack (cont'd)
Method calls go on a stack (cont'd)

When you're doing it by hand (e.g. on an exam or worksheet),


it's better to just use a single stack. Put a line through methods
when they return.

We will do examples of the stack-based recursion tracing


methodology in class.
Recursive method debugging
Watching a recursive method run (putting multiple copies of
the method on the call stack) is a really useful tool for
understanding recursion.

BlueJ's debugger is incredibly good at this. Other IDEs that


have debuggers will perform exactly the same operation –
however, BlueJ's interface is simple, elegant, and great at
showing you how call stacks work, and that each method
has its own copies of local variables.

Some video examples on the next slide.


Recursive method debugging (cont'd)
Remember that each copy of a method, placed on the
call stack, will have its own copy of the method's local
variables.

These videos showing the "call stack" using BlueJ's


debugger may help:

• numEars method

• factorial method

• fibonacci method
The two parts of a recursive algorithm
Every recursive algorithm always has at least 2 parts:

• Base case(s)
o These determine when to stop (when no more

recursive calls should take place)

• Recursive call(s)
o Calls the same algorithm (i.e., itself) to assist in

solving the problem


o The goal is to break the problem up into smaller and

smaller parts until the entire problem can be solved


(by solving smaller individual parts)
Random points on recursion
A few things to remember, in no particular order:

• Recursion is really just another form of looping, or repeating


a particular process. Recursion just makes some problems
vastly simpler (than an iterative solution)

• With recursion, you're making the assumption that you will


eventually solve the problem (reach the base case)

• If a recursive method does not eventually reach its base


case, infinite recursion will occur
• Eventually, Java runs out of space to store method calls
and will tell you a StackOverflowException has occurred
Increment / decrement operators
Be careful when using post increment / decrement operators (+
+ and --)!

When placed after a variable, a post increment operator adds


one to the variable after the statement runs. Example:

int a = 4;
System.out.print(a++); //line 2
System.out.print(" " + a);

Would print: 4 5

...because a is incremented after the print statement on line 2


runs, above.
Increment / decrement ops (cont'd)
With recursive methods, the post increment operator would be
applied after the method call, leading to some very confusing errors:

public int numEars(int bunnies)


{
if (bunnies == 1)
return 2;

else
return 2 + numEars(bunnies--);
}

The above would cause a stack overflow (infinite recursion) ,


because bunnies is never actually going down until after the
recursive call happens!
Help! My brain splode!
Recursion is an entirely new way of thinking and will most likely
be pretty confusing at first. Just like with all things
programming-related, you will get better with practice.

Recursion takes quite a while to get good at, and you do NOT
need to be a recursion expert for the AP exam, you simply
need to be able to trace recursive method calls.

For more help with tracing recursive method calls, this site
helps explain the "stack-based" methodology (that I favor as it
tends to work for many students) very well:

apcomputersciencetutoring.com/exam-review/trace-recursive-methods/

You might also like