What is Recursion?
•
The word recursive means
: “having the characteristic of coming up again, or repeating.”• You may have seen a set of gaily-painted Russian dolls that fit i id th
inside one another.
• Inside the first doll is a smaller doll, inside of which is an even smaller doll, inside of which is yet a smaller doll, and so on. A recursive algorithm is like such a set of Russian dolls
• A recursive algorithm is like such a set of Russian dolls.
• It reproduces itself with smaller and smaller versions of itself until a version is reached that can no longer be subdivided—that is, until the smallest doll is reached
the smallest doll is reached.
• The recursive algorithm is implemented by using a method that makes recursive calls to itself; analogous to taking the dolls apart one by one.
What is Recursion?
What is Recursion?
• It is a problem-solving process
B k bl i id i l b ll bl
• Breaks a problem into identical but smaller problems • Eventually you reach a smallest problem
– Answer is obvious or trivial
• Using that solution enables you to solve the previous problems • Using that solution enables you to solve the previous problems
– Eventually the original problem is solved
• Recursive call: A method call in which the method being called is the same as the one making the call
• Direct recursion: Recursion in which a method directly calls itself • Indirect recursion: Recursion in which a chain of two or more
method calls returns to the method that originated the chain (Indirect recursion occurs when method A calls method B and method B
Java and recursion
Java and recursion
• In Java, any method can invoke another method.
y
A method can even invoke itself!
• When a method invokes itself, it is making a
recursive call
recursive call
• Recursion is a powerful programming technique.
However, you must be careful when using
i
R
i
l ti
b l
recursion. Recursive solutions can be less
efficient than iterative solutions to the same
problem.
A Classic Example of Recursion
A Classic Example of Recursion
•
n
n
! (read “
! (read
n
n
factorial”) is used to calculate
factorial ) is used to calculate
the number of permutations of
n
elements.
• One mathematical description of
n
! is
A Classic Example of Recursion
A Classic Example of Recursion
• Consider the case of 4!. Because
Consider the case of 4!. Because
n
n
> 0, we use the
0, we use the
second part of the definition:
• 4! = 4 * 3 * 2 * 1 = 24
W
l
!
ith
t
i
th th
d t
• We can also express
n
! without using the three dots:
• This is a recursive definition because we express the
f
t i l f
ti
i t
f it
lf
A Classic Example of Recursion
A Classic Example of Recursion
• Let’s consider the recursive calculation of
Let s consider the recursive calculation of
4!. Because 4 is not equal to 0, we use the
second half of the definition:
• 4! = 4 * (4 - 1)! = 4 * 3!
• Of course, we can’t do the multiplication
Of course, we can t do the multiplication
yet, because we don’t know the value of
3!.
A Classic Example of Recursion
A Classic Example of Recursion
• Notice when the recursive calls stop. They stop
p
y
p
when we have reached a case for which we
know the answer without resorting to a recursive
definition In this example 0! = 1 directly from the
definition. In this example 0! = 1 directly from the
definition without having to resort to recursion.
• The case (or cases) for which an answer is
The case (or cases) for which an answer is
explicitly known is called the base case.
Base and General cases
Base and General cases
•
Base case
Base case
The case for which the solution
The case for which the solution
can be stated nonrecursively
•
General (recursive) case
The case for
•
General (recursive) case
The case for
which the solution is expressed in terms of
a smaller version of itself
a smaller version of itself
•
Recursive algorithm
A solution that is
d i t
f ( )
ll
expressed in terms of (a) smaller
Coding the Factorial Function
bli t ti i t f t i l(i t b ) public static int factorial(int number) {
if (number == 0)
return 1; // Base case l
else
return (number * factorial(number – 1)); // General case }
• Let’s trace this method with an original number of 4:
g
• Call 1 number is 4. Because number is not 0, the
else
branch is taken. The
return
statement cannot be
completed until the recursive call to factorial with
p
number – 1 as the argument has been completed.
• Call 2 number is 3. Because number is not 0, the
else
tracing the factorial method
• Call 3 number is 2. Because number is not 0, the
else
branch is taken. The
return
statement cannot be
l t d
til th
i
ll t f
t i l
ith
completed until the recursive call to factorial with
number – 1 as the argument has been completed.
• Call 4 number is 1. Because number is not 0, the else
branch is taken. The return statement cannot be
completed until the recursive call to factorial with
number – 1 as the argument has been completed.
• Call 5 number is 0. Because number equals 0, this call to
the method returns, sending back 1 as the result.
• Call 4 The return statement in this copy can now be
py
completed. The value to be returned is number
tracing the factorial method
• Call 3 The return statement in this copy can now be
completed. The value to be returned is number
(which is 2) times 1. This call to the method returns,
sending back 2 as the result.
• Call 2 The return statement in this copy can now be
py
completed. The value to be returned is number
(which is 3) times 2. This call to the method returns,
sending back 6 as the result.
• Call 1 The return statement in this copy can now be
completed. The value to be returned is number
(which is 4) times 6. This call to the method returns,
(
)
,
sending back 24 as the result.
• Because this is the last of the calls to factorial, the
recursive process is over. The value 24 is returned as
The iterative solution of factorial method
The iterative solution of factorial method
• The iterative solution is simpler and much more efficient because starting a new iteration of a loop is a faster operation than calling a starting a new iteration of a loop is a faster operation than calling a method.
• Let’s look at an iterative solution to the problem:
// Iterative solution
public static int factorial(int number) {
int value = 1;
for (int count = 2; count <= number; count++) {
value = value * count; }
Writing Recursive Methods
• You can use the following approach to write any recursive method:
1 G t t d fi iti f th bl t b l d (Thi f i
• 1. Get an exact definition of the problem to be solved. (This, of course, is the first step in solving any programming problem.)
• 2. Determine the size of the problem to be solved on this call to the method. On the initial call to the method, the size of the whole problem is expressed in the value(s) of the parameter(s)
in the value(s) of the parameter(s).
• 3. Identify and solve the base case(s) in which the problem can be expressed nonrecursively.
• 4. Identify and solve the general case(s) correctly in terms of a smaller case of the same problem a recursive call
of the same problem— a recursive call.
• In the case of factorial, the definition of the problem is summarized in the definition of the factorial function. The size of the problem is the number of values to be multiplied: n.
• The base case occurs when n = 0 in which case we take the nonrecursive • The base case occurs when n = 0, in which case we take the nonrecursive
path.
Count down example
Count down example
• /** Task: Counts down from a given positive integer.
g
p
g
* @param integer an integer > 0 */
public static void
countDown(
int
value)
{ System.out.println(value);
if
(value > 1)
Tracing the recursive call
countDown(3)
Tracing the recursive call
countDown(3)
Tracing the recursive call
countDown(3)
Note: the recursive method will use more
memory than an it ti th d d iterative method due
Example
Example
• Task: Compute the sum
Task: Compute the sum
1 + 2 + 3 + … + n for an integer n > 0
public static int sumOf(int n) { int sum;
if (n = = 1)( )
sum = 1; // base case
else
sum = sumOf(n - 1) + n; // recursive call
Tracing the recursive call
sumOf(3)
A Recursive Version of contains()method
()
• Let’s apply this approach to writing a recursive
version of the contains() method for our abstract
List class
List class.
public boolean contains(Object anEntry)
• The contains problem can be decomposed into
p
p
smaller problems by deciding if item is in the first
position of the list or in the rest of the list.
• More formally contains (anEntry=return (is
• More formally contains (anEntry=return (is
A Recursive Version of contains()method
ecu s e
e s o o co ta s() et od
• We can answer the first question just by comparing anEntry to entry[0].
• But how do we know whether anEntry is in the rest of the list? If only we had a • But how do we know whether anEntry is in the rest of the list? If only we had a
method that would search the rest of the list. But we do have one! The contains method searches for a value in a list.
• We simply need to start searching at position 1, instead of at position 0 (a smaller case).
• To do this, we need to pass the search starting place to contains() as a parameter. Each recursive call to contains() passes a starting location that is one location more than its own starting location.
• But how do we know when to stop?
• Within the code for the recursive contains() method we can use length 1 to mark • Within the code for the recursive contains() method we can use length – 1 to mark
the end of the list, so we can stop the recursive calls when our starting position is that value.
• We use the following private method specification to be called by contains () method • public boolean isThere (Object item, int startPosition);p ( j )
• // task: Determines if element matching item is on this list between • // startPosition and the end of the list
A Recursive Version of contains()method
ecu s e
e s o o co ta s() et od
• To search the whole list, we would invoke the method with the statement if (i Th ( E t 0))
if (isThere(anEntry, 0))
• The general case of this approach is the part that searches the rest of the list. This case involves a recursive call to isThere, specifying a smaller part
f th t b h d
of the array to be searched:
• return isThere(item, startPosition + 1);
• By using the expression startPosition + 1 as the argument, we have
effectively diminished the size of the problem to be solved by the recursive
ll Th t i hi th li t f t tP iti 1 t It 1 i
call. That is, searching the list from startPosition + 1 to numItems – 1 is a smaller task than searching from startPosition to numItems – 1.
• Finally, we need to know when to stop searching. In this problem, we have two base cases:
(1) h th l i f d ( t t ) d
• (1) when the value is found (return true), and
• (2) when we have reached the end of the list without finding the value
A Recursive Version of contains()method
ecu s e
e s o o co ta s() et od
• The code for the recursive isThere method follows
public boolean isThere (Object item, int startPosition)
// Returns true if item is on this list; otherwise, returns false {{
if (item.compareTo(Entry[startPosition]) == 0) // If they match return true;
else if (startPosition == (length – 1)) // If end of list else if (startPosition (length 1)) // If end of list return false;
Recursively Processing a Linked Chain
T
it
th d th t
h i
• To write a method that processes a chain
of linked nodes recursively
– Use a reference to the chain's first node as the
method's parameter
public void display()
• Then process
the first node
public void display()
{ displayChain(firstNode); System.out.println(); } // end display
– Followed by the
rest of the chain
private void displayChain(Node nodeOne) { if (nodeOne != null)
{ System.out.print(nodeOne.data + " "); displayChain(nodeOne next);
displayChain(nodeOne.next); }
Time Efficiency of Recursive Methods
Time Efficiency of Recursive Methods
• For the
For the
countDown
countDown
method
method
public static void countDown(int integer)
{ System out println(integer); { System.out.println(integer);
if (integer > 1)
countDown(integer - 1); } // end countDown
Towers of Hanoi
Towers of Hanoi
O f fi h b di k i h h i h
• One of your first toys may have been a disk with three pegs with colored circles of different diameters. If so, you probably spent countless hours moving the circles from one peg to another. If we put some constraints on how the circles or discs can be moved, we h d lt ll d th T f H i Wh th
have an adult game called the Towers of Hanoi. When the game begins, all the circles are on the first peg in order by size, with the smallest on the top. The object of the game is to move the circles, one at a time, to the third peg. The catch is that a circle cannot be
l d t f th t i ll i di t Th iddl
placed on top of one that is smaller in diameter. The middle peg can be used as an auxiliary peg, but it must be empty at the beginning and at the end of the game.
• The circles can only be moved one at a time.y
• To get a feel for how this might be done, let’s look at some sketches of what the configuration must be at certain points if a solution is possible. We use four circles or discs. The beginning configuration is:
Towers of Hanoi
Towers of Hanoi
• To move the largest circle (circle 4) to peg
To move the largest circle (circle 4) to peg
3, we must move the three smaller circles
to peg 2 (this cannot be done with 1
to peg 2 (this cannot be done with 1
move). Then circle 4 can be moved into its
final place:
Towers of Hanoi
Towers of Hanoi
• Algorithm for solution with 1 disk as the
Algorithm for solution with 1 disk as the
base case
Algorithm solveTowers(numberOfDisks, startPole, tempPole, endPole) if (numberOfDisks == 1)
Move disk from startPole to endPole
Move disk from startPole to endPole
else
{
solveTowers(numberOfDisks-1, startPole, endPole, tempPole)
Move disk from startPole to endPole
Fibonacci numbers
Fibonacci numbers
• First two numbers of sequence are 1 and 1
q
• Successive numbers are the sum of the previous two
– 1, 1, 2, 3, 5, 8, 13, …
• This has a natural looking recursive solution
• This has a natural looking recursive solution
– Turns out to be a poor (inefficient) solution
• The recursive algorithm
•
Algorithm
Fibonacci(n)
if
(n <= 1)
return
1
else
Fibonacci numbers
Fibonacci numbers
Time efficiency grows exponentially with n