Data Structures and Abstractions with Java™
5th Edition
Module 9 -
Recursion
Including:
Chapter 9 – Recursion
Chapter 14 – Problem
Solving with Recursion
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
“To iterate is human, to recurse divine.” L. Peter Deutsch
2
3
4
What Is Recursion?
• Consider hiring a contractor to build
– He hires a subcontractor for a portion of the job
– That subcontractor hires a sub-subcontractor to do a
smaller portion of job
• The last sub-sub- … subcontractor finishes
– Each one finishes and reports “done” up the line
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Example: The Countdown
FIGURE 9-1 Counting down from 10
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Example: The Countdown
/** Counts down from a given positive integer.
@param integer An integer > 0.
*/
public static void countDown(int integer)
{
System.out.println(integer);
if (integer > 1)
countDown(integer - 1);
} // end countDown
Recursive Java method to do countDown.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Definition
• Recursion is a problem-solving process
– Breaks a problem into identical but smaller problems.
• A method that calls itself is a recursive method.
– The invocation is a recursive call or recursive
invocation.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Design Guidelines
• Method must be given an input value
• Method definition must contain logic that involves this
input, leads to different cases
• One or more cases should provide solution that does not
require recursion
– Else infinite recursion
• One or more cases must include a recursive invocation
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Programming Tip
• Iterative method contains a loop
• Recursive method calls itself
• Some recursive methods contain a loop and call
themselves
– If the recursive method with loop uses while, make
sure you did not mean to use an if statement
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Tracing a Recursive Method
FIGURE 9-2 The effect of the method call countDown(3)
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Tracing a Recursive Method
FIGURE 9-3 Tracing the execution of countDown(3)
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Stack of Activation Records
• Each call to a method generates an activation record
• Recursive method uses more memory than an iterative
method
– Each recursive call generates an activation record
• If recursive call generates too many activation records,
could cause stack overflow
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Stack of Activation Records
FIGURE 9-4 The stack of activation records during the execution of the call countDown(3)
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
A Methodized Approach to the Formulation of Recursive Algorithms
• For problems with recursive solutions, the
methodology
– Is directly applicable to many of them
– Can be modified to adapt it to most of them
• Four steps
1. Determine the base case
2. Determine the reduced problem
3. Determine the general solution
4. Combine the base case, reduced problem and general
solution to form the recursive algorithm15
15
Determining the Base Case
• Identify an instance of the problem whose solution is know.
Could be an instance when
– The solution is defined, or
– The instance is a special case, or
– There is a trivial solution
• Often occurs when n ==0 or n ==1
• Examples
– 0! ≡ 1, a string of length 1, an empty list, a found search
item
16
16
Determining the Reduced Problem
• Requires the most imagination and creativity
• Look for a problem
– Similar to the original problem
– Usually a small step away from the original problem, in the
direction of the base case
– That degenerates into the base case when repeatedly
reduced
• It should be in between the original problem and the
base case, usually very close to the original problem,
and must eventually become the base case (when
repeatedly reduced)
17
17
Determining the General Solution
• Consider how the reduced problem can be used to
– Generate the original problem
– Solve the original problem
• For example
– Original problem n!
– Reduced problem: (n-1)!
– General solution
▪ Original problem n! = n * reduced problem = n * (n-1)!
18
18
Determining the Reduced Problem for n!
(the base case is 0!)
• The reduced problem should be:
– Similar to the original problem
▪ Something factorial
– A small step away from the original problem in the
direction of the base case
▪ (n-1)! or (n-2)! or (n-3!) or ….
– That degenerates into the base case when repeatedly
reduced
▪ Only (n-1)! will degenerate in to 0! for all n
• Therefore (n-1) is chosen as the reduced problem
19
19
Terminology of Recursive Algorithms
Illustrated Using the Problem: n!
• Base case ( e.g. 0! = 1 )
– The known portion of the problem
• Reduced problem ( e.g., (n-1)! )
– A problem very “close” to the original problem
– Slightly closer to the base case
– When reduced, degenerates into the base case
• General solution ( e.g., n*(n-1)! )
– The solution to the original problem expressed in terms
of the reduced problem
20
20
Code of the Recursive Algorithm for n!
1. public static long nFactorial(long n)
2. { long nMinus1Factorial;
3. if(n == 0) // base case
4. return ( 1 );
5. else
6. { // reduced problem
7. nMinus1Factorial = nFactorial(n-1); // recursion
8. // general solution
9. return ( n * nMinus1Factorial);
10. }
11. }
21
Trace of the Evaluation of 4!
4! 24
return (4 * 3!) 6
return (3 * 2!) 2
return (2 * 1!) 1
return (1 * 0!) 1
0!
22
Recursive Methods That Return a Value
/** @param n An integer > 0.
@return The sum 1 + 2 + ... + n. */
public static int sumOf(int n)
{
int sum;
if (n == 1)
sum = 1; // Base case
else
sum = sumOf(n - 1) + n; // Recursive call
return sum;
} // end sumOf
Recursive method to calculate
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
FIGURE 9-5 Tracing the execution of sumOf(3)
FIGURE 9-5 Tracing the execution of sumOf(3)
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursive Algorithm for Xⁿ
• Base case
– Problems involving an integer n usually have their base case for
n=0 or n=1. Use n=0 because x^0 ≡ 1
• Reduced problem
•Candidates are x^(n-1), x^(n-2), x^(n-3)
•x^(n-1) is the only one that will become the base case for all n
• General solution
•xⁿ = x* [x^(n-1)] = x * reduced problem
• Combine
25
25
Recursive Coding of Xⁿ
1. public static float xToN(double x, int n)
2. { if(x == 0) // base case
3. return 1;
4. else
5. { int rp = xToN(x, n-1); // reduced problem (recursion)
6. float gs = x* rp; // calculate the general solution
7. return gs; // return the general solution
8. {
26
26
Recursive Algorithm for the nth Term, F n in the Fibonacci Sequence
(multiple base cases)
• Base case
– A defined solution for n = 0 and n = 1.
– F1 ≡ 1, F2 ≡ 1
• Reduced Problem
– Fn-1 and Fn-2 are close to original problem, and will
become one of the base cases when further reduced
• General solution (by definition)
– Fn ≡ Sum of reduced problems = Fn-1 + Fn-2
• Combine
27
27
Recursive Coding of the nth Term of the Fibonacci Sequence
1. public static long fibonacci(int n)
2. { if(n == 1 || n == 2) //one of the 2 base cases
3. return 1;
4. else
5. { long rp1 = fibonacci(n - 1); // first reduced problem
6. long rp2 = fibonacci(n - 2); // second reduced problem
7. gs = rp1 + rp2; // general solution
8. return gs;
9. }
10. }
28
28
Recursively Processing an Array
/** Displays the integers in an array.
@param array An array of integers.
@param first The index of the first integer displayed.
@param last The index of the last integer displayed,
0 <= first <= last < array.length. */
public static void displayArray(int[] array, int first, int last)
Given definition of a recursive method to display array.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursively Processing an Array
public static void displayArray(int array[], int first, int last)
{
System.out.print(array[first] + " ");
if (first < last)
displayArray(array, first + 1, last);
} // end displayArray
Starting with array[first]
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursively Processing an Array
public static void displayArray(int array[], int first, int last)
{
if (first <= last)
{
displayArray(array, first, last - 1);
System.out.print(array[last] + " ");
} // end if
} // end displayArray
Starting with array[last]
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursively Processing an Array
FIGURE 9-6 Two arrays with their middle elements within their left halves
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursively Processing an Array
public static void displayArray(int array[], int first, int last)
{
if (first == last)
System.out.print(array[first] + " ");
else
{
int mid = (first + (last - first) / 2; Why?
displayArray(array, first, mid);
displayArray(array, mid + 1, last);
} // end if
} // end displayArray
Processing array from middle.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursive Algorithm to Output a String of Length n in Reverse Order
• Base case
– Problems involving an integer n usually have their
base case for n=0 or n=1. Use n = 0, no output
• Reduced problem
– Candidates are output n-1, or n-2, or n-3, …
characters in reverse order
– Output n-1 characters in reverse order is the only
one that will become the base case for all n
• General solution
– Output the nth character, output the first n-1
characters in reverse order
• Combine 34
34
Code to Output a String of Length n in Reverse Order
1. public static void stringReverse(String s, int n)
2. { if(n == 0) // base case
3. return;
4. else // general solution
5. { System.out.print(s.charAt(n-1)); // output last character
6. stringReverse(s, n-1); // reduced problem (recursion)
7. }
8. }
35
35
Code to Output a String of Length n in
Reverse Order (hidden base case)
This can be rewritten with a hidden base case
1. public static void stringReverse(String s, int n)
2. { if(n > 0) // general case
3. {
4. System.out.print(s.charAt(n-1)); // output last
character
5. stringReverse(s, n-1); // reduced problem (recursion)
6. }
7. }
36
37
Displaying a Bag
public void display()
{
displayArray(0, numberOfEntries - 1);
} // end display
private void displayArray(int first, int last)
{
System.out.println(bag[first]);
if (first < last)
displayArray(first + 1, last);
} // end displayArray
Recursive method that is part of an implementation of an ADT often is private.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursively Processing a Linked Chain
public void display()
{
displayChain(firstNode);
} // end display
private void displayChain(Node nodeOne)
{
if (nodeOne != null)
{
System.out.println(nodeOne.getData()); // Display data in first node
displayChain(nodeOne.getNextNode()); // Display rest of chain
} // end if
} // end displayChain
Display data in first node and recursively display data in rest of chain.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursively Processing a Linked Chain
public void displayBackward()
{
displayChainBackward(firstNode);
} // end displayBackward
private void displayChainBackward(Node nodeOne)
{
if (nodeOne != null)
{
displayChainBackward(nodeOne.getNextNode());
System.out.println(nodeOne.getData());
} // end if
} // end displayChainBackward
Displaying a chain backwards. Traversing chain of linked nodes in reverse order easier when
done recursively.
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Time Efficiency of Recursive Methods
public static void countDown(int n)
{
System.out.println(n);
if (n > 1)
countDown(n - 1);
} // end countDown
Using proof by induction, we conclude method is O(n).
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Time Efficiency of Computing xn
xn = (xn/2)2 when n is even and positive
xn = x (x (n - 1)/2)2 when n is odd and positive
x0 = 1
Efficiency of algorithm is O(log n)
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Tail Recursion
• When the last action performed by a recursive
method is a recursive call.
• In a tail-recursive method, the last action is a recursive call
• This call performs a repetition that can be done by using
iteration.
• Converting a tail-recursive method to an iterative one is
usually a straightforward process.
public static void countDown(int n)
{
System.out.println(n);
if (n > 1)
countDown(n - 1);
} // end countDown
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Using a Stack Instead of Recursion
• Converting a recursive method to an iterative one
public static void countDown(int integer)
{
if (integer >= 1)
{
System.out.println(integer);
countDown(integer - 1);
} // end if
} // end countDown
• An iterative version
public static void countDown(int integer)
{
while (integer >= 1)
{
System.out.println(integer);
integer = integer − 1;
} // end while
} // end countDown
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Using a Stack Instead of Recursion
• An iterative displayArray to maintain its own stack
public void displayArray(int first, int last)
{
boolean done = false;
StackInterface<Record> programStack = new LinkedStack<>();
programStack.push(new Record(first, last));
while (!done && !programStack.isEmpty())
{
Record topRecord = programStack.pop();
first = topRecord.first;
last = topRecord.last;
if (first == last)
System.out.println(array[first] + " ");
else
{
int mid = first + (last - first) / 2;
// Note the order of the records pushed onto the stack
programStack.push(new Record(mid + 1, last));
programStack.push(new Record(first, mid));
} // end if
} // end while
} // end displayArray
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Interesting Problems Whose Solutions Involve
Recursion
• Knight’s tour:
Q
– move a knight around a checkerboard such that it Q
Q
visits each square only once Q
Q
• Queens Eight: Q
Q
– Place eight queens on a checkerboard Q
such that they cannot capture each other 5 8 2 1 3 4 9 7 6
3 4 9 5 6 7 1 2 8
• Numeric puzzle: 7
8
6
2
1
3
9
4
2
9
8
1
4
5
3
6
5
4 7 5 3 8 6 2 9 1
– Enter a 1, or 2, …, or 9 in each cell 1 9 6 7 5 2 3 8 4
of a 9x9 grid such that each row, 2 5 8 6 1 9 7 4 3
column, and 3x3 sub-grid contains 19 9 3 7 8 4 5 6 1 2
6 1 4 2 7 3 8 5 9
• Towers
Move oneofring
Hanoi:
at a time, never placing a large ring
46
on a smaller ring 46
Simple Solution to a Difficult Problem
FIGURE 14-1 The initial configuration of the Towers of Hanoi for three disks
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Simple Solution to a Difficult Problem
• Rules:
– Move one disk at a time. Each disk moved must be
the topmost disk.
– No disk may rest on top of a disk smaller than itself.
– You can store disks on the second (extra) pole
temporarily, as long as you observe the previous two
rules.
© 2015 Pearson Education, Inc., Upper Saddle©River,
Copyright 2019,NJ. All2012
2015, rightsPearson
reserved.
Education, Inc. All Rights Reserved
Simple Solution to a Difficult Problem (Part 1)
FIGURE 14-2 Sequence of moves for solving Towers of Hanoi problem with 3 disks
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Simple Solution to a Difficult Problem (Part 2)
FIGURE 14-2 Sequence of moves for solving Towers of Hanoi problem with 3 disks
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
A Smaller Problem
FIGURE 14-3 The smaller problems in a recursive solution for four disks
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Solutions
Algorithm to move numberOfDisks disks from startPole to endPole using tempPole
as a spare according to the rules of the Towers of Hanoi problem
if (numberOfDisks == 1)
Move disk from startPole to endPole
else
{
Move all but the bottom disk from startPole to tempPole
Move disk from startPole to endPole
Move all disks from tempPole to endPole
}
Recursive algorithm to solve any number of disks.
Note: for n disks, solution will be 2n – 1 moves
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Recursive Solution to the Towers of Hanoi
• Base case S D E S D E
– A trivial solution (n = 1): move 1 ring from one tower to another
• Reduced problem
– Candidates are move n-1, or n-2, or n-3, … rings from one tower
to another
– Move n-1 rings is the only one that will become the base case for
all n
• General solution
– Move n-1 rings from S to E (Source to Extra tower)
– Move 1 ring from S to D (Source to Destination tower)
– Move n-1 rings from E to D (Extra to Destination tower)
• Combine
53
53
Code of the Recursive Solution to the Towers of Hanoi
1. public static void hanoi(int n, int S, int D, int E)
2. { if(n == 1) // base case
3. System.out.println("move 1 ring from tower " + S +
" to tower " + D);
4. else // general solution
5. { hanoi(n-1, S, E, D); // reduced problem
6. System.out.println("move 1 ring from tower " + S +
" to tower " + D);
7. hanoi(n-1, E, D, S); // reduced problem
8. }
9. } 54
54
55
Poor Solution to a Simple Problem
F0 = 1
F1 = 1
Fn = Fn - 1 + Fn - 2 when n ≥ 2
Algorithm Fibonacci(n) if (n <= 1)
return 1
else
return Fibonacci(n − 1) + Fibonacci(n − 2)
Algorithm to generate Fibonacci numbers.
Why is this inefficient?
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Poor Solution to a Simple Problem
FIGURE 14-4a The computation of the Fibonacci number F6
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Poor Solution to a Simple Problem
FIGURE 14-4b The computation of the Fibonacci number F6
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Indirect Recursion
• Example
– Method A calls Method B
– Method B calls Method C
– Method C calls Method A
• Difficult to understand and trace
– But does happen occasionally
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Indirect Recursion
• Consider evaluation of validity of an algebraic expression
– Algebraic expression is either a term or two terms
separated by a + or – operator
– Term is either a factor or two factors separated by a *
or / operator
– Factor is either a variable or an algebraic expression
enclosed in parentheses
– Variable is a single letter
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Indirect Recursion
FIGURE 14-5 An example of indirect recursion
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Backtracking
FIGURE 14-6 A two-dimensional maze with one entrance and one exit
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Backtracking
FIGURE 14-7 A solution to the four-queens problem
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Backtracking - Queens Solution (Part 1)
FIGURE 14-8 Solving the four-queens problem by placing
one queen at a time in each column
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved
Backtracking - Queens Solution (Part 2)
FIGURE 14-8 Solving the four-queens problem by placing
one queen at a time in each column
Copyright © 2019, 2015, 2012 Pearson Education, Inc. All Rights Reserved