2 Recursion
2 Recursion
These slides has been extracted, modified and updated from original slides of :
• Data Structures and Algorithms in Java, 5th edition. John Wiley& Sons, 2010. ISBN 978-0-470-38326-1.
• Dr. Hanna’s slides (http://aimanhanna.com/concordia/comp352/index.htm)
❑ As a Java method:
// recursive factorial function
public static int recursiveFactorial(int n) {
if (n == 0) return 1; // base case
else return n * recursiveFactorial(n- 1); // recursive case
}
Recursion 2
Content of a Recursive Method
❑ Base case(s)
◼ Also referred to as stopping cases. These are the
cases where the method performs NO more
recursive calls.
◼ There should be at least one base case.
◼ Every possible chain of recursive calls must
eventually reach a base case.
❑ Recursive calls
◼ Calls to the method itself.
◼ Each recursive call should be defined so that it
makes progress towards a base case.
Recursion 3
Visualizing Recursion
❑ Example
❑ Recursion trace
return 4*6 = 24 final answer
A box for each
call
◼
recursive call
recursiveFactorial (4)
Recursion 4
Recursion & The Stack
❑ A running Java program maintains a private memory
area called the stack, which is used to keep track of
the methods as they are invoked.
Recursion 5
Recursion & The Stack
main()
fun5():
{…
PC = 328
fun1(); m=2
… n=5
} fun1():
Frames PC = 229
fun1() y=7
{…
fun5();
main():
…
PC = 24
} Java Stack x = 10
Recursion 6
Recursion & The Stack
❑ The heap is another memory area that is maintained
for a running program.
Recursion 9
Example: Reversing an Array
Algorithm ReverseArray(A, i, j):
Input: An array A and nonnegative integer
indices i and j
Output: The reversal of the elements in A
starting at index i and ending at j
if i < j then
Swap A[i] and A[ j]
ReverseArray(A, i + 1, j - 1)
return
Recursion 10
Defining Arguments for Recursion
❑ In creating recursive methods, it is important
to define the methods in ways that facilitate
recursion.
Recursion 13
Recursive Squaring Method
Algorithm Power(x, n):
Input: A number x and integer n = 0
Output: The value xn
if n = 0 then
return 1
if n is odd then
y = Power(x, (n - 1)/ 2)
return x · y ·y
else
y = Power(x, n/ 2)
return y · y
Recursion 14
Analysis
Algorithm Power(x, n):
Input: A number x and
integer n = 0 Each time we make a
Output: The value xn recursive call we halve
the value of n; hence,
if n = 0 then we make log n recursive
return 1 calls. That is, this
if n is odd then method runs in O(log n)
y = Power(x, (n - 1)/ 2) time.
return x · y · y
else It is important that we
use a variable twice
y = Power(x, n/ 2) here rather than calling
return y · y the method twice.
Recursion 15
Tail Recursion
❑ Tail recursion occurs when a linearly recursive
method makes its recursive call as its last step; as in
the array reversal method.
Recursion 18
Example: Summing Array Elements
❑ The following provides an example of a
binarySum(0, 8) trace, where each box indicates the
starting index and the number of elements to sum.
0, 4 4, 4
0, 2 2, 2 4, 2 6, 2
0, 1 1, 1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1
19
Recursion
Example: Fibonacci Numbers
❑ In mathematics, the Fibonacci numbers are the
numbers in the following integer sequence:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
Recursion 21
Example: Fibonacci Numbers
❑ Analysis: Let nk be the number of recursive calls
(notice that this is not the value) by binaryFib(k)
◼ n0 = 1
◼ n1 = 1
◼ n2 = n1 + n0 + 1 = 1 + 1 + 1 = 3
◼ n3 = n2 + n1 + 1 = 3 + 1 + 1 = 5
◼ n4 = n3 + n2 + 1 = 5 + 3 + 1 = 9
◼ n5 = n4 + n3 + 1 = 9 + 5 + 1 = 15
◼ n6 = n5 + n4 + 1 = 15 + 9 + 1 = 25
◼ n7 = n6 + n5 + 1 = 25 + 15 + 1 = 41
◼ n8 = n7 + n6 + 1 = 41 + 25 + 1 = 67.
❑ Note that nk at least doubles every other time.
❑ In fact, nk > 2k/2. It is exponential!
Recursion 22
Example: Fibonacci Numbers
❑ The main problem with binaryFib(k) approach is that
the computation of Fibonacci numbers is really a
linearly recursive problem, in spite of its look where Fk
depends on Fk-1 and Fk-2.
Recursion 23
A Better Fibonacci Algorithm
❑ Use linear recursion instead
Algorithm linearFibonacci(k):
Input: A nonnegative integer k
Output: Pair of Fibonacci numbers (Fk , Fk-1)
if k = 1 then
return (k, 0)
else
(i, j) = linearFibonacci(k - 1)
return (i +j, i)
// notice that the values are retuned (however, not both are
displayed)
❑ linearFibonacci makes k-1 recursive calls, so total calls is k.
➔ See LinearFib.java & BinaryFibStack.java
Recursion 24
A Better Fibonacci Algorithm
For instance (note: Fib is short for linearFibonacci),
❑ Fib(2) ➔ (i+j, i) is (1,1) ➔ Will be displaying 1
❑ Fib(3) ➔ (i+j, i) is (2,1) ➔ Will be displaying 2
❑ :
❑ Fib(12) ➔ (i+j, i) is (144,89) ➔ Will be displaying
144
Recursion 25
Binary Recursion
Another Example
❑ The English Ruler:
◼ Print the ticks and numbers like an English ruler
Recursion 26
Slide by Matt Stallmann included with permission.
drawTicks(length)
drawTicks( length − 1 )
drawTicks( length − 1 )
Recursion 27
Recursive Drawing Method
❑ The drawing method is drawTicks (3) Output
recursive definition
drawTicks (1)
drawTicks (0)
drawTicks (0)
◼ An interval with a central drawOneTick (3)
tick length L−1 drawTicks (2)
(previous pattern repeats )
Recursion 28
Java Implementation (1)
// draw ruler
public static void drawRuler(int nInches, int majorLength) {
drawOneTick(majorLength, 0); // draw tick 0 and its label
for (int i = 1; i <= nInches; i++) {
drawTicks(majorLength- 1); // draw ticks for this inch
drawOneTick(majorLength, i); // draw tick i and its label
}
}
Note the two
// draw ticks of given length recursive calls
public static void drawTicks(int tickLength) {
if (tickLength > 0) { // stop when length drops to 0
drawTicks(tickLength- 1); // recursively draw left ticks
drawOneTick(tickLength); // draw center tick
drawTicks(tickLength- 1); // recursively draw right ticks
}
}
Recursion 29
Java Implementation (2)
// draw a tick with no label
public static void drawOneTick(int tickLength) {
drawOneTick(tickLength, - 1); // -1 will avoid printing the label
}
Recursion 30
Multiple Recursion
❑ Multiple recursion:
◼ makes potentially many recursive calls
◼ not just one or two
❑ Motivating example:
◼ Coping folders (directories)
◼ summation puzzles
pot + pan = bib
dog + cat = pig
boy + girl = baby
Recursion 31
Example of Multiple Recursion
Algorithm CopyFolder(folder):
Input: A directory folder, which possibly includes files and subfolders
Output: A copy of the given folder with all its files and subfolders
Recursion 32
Example of Multiple Recursion
Algorithm PuzzleSolve(k,S,U):
Input: Integer k, sequence S, and set U (universe of elements to
test)
Output: Enumeration of all k-length extensions to S using elements
in U without repetitions
for all e in U do
Remove e from U {e is now being used}
Add e to the end of S
if k = 1 then
Test whether S is a configuration that solves the puzzle
if S solves the puzzle then
return “Solution found: ” S
else
PuzzleSolve(k - 1, S,U)
Add e back to U {e is now unused}
Remove e from the end of S
Recursion 33
Slide by Matt Stallmann
included with permission.
Recursion 34
Visualizing PuzzleSolve
❑ Notice that the number of concurrently active calls can
still be limited with multiple recursion.
❑ For instance, the number of active calls of CopyFolder
depends on how many nested subfolders may exist at
a time and not on the total number of subfolders in
the directory. Initial call
PuzzleSolve (3,(),{a,b,c})