Understanding Recursive Functions
Understanding Recursive Functions
Recursion
1
Finding a Recursive Solution
Each successive recursive call should bring you
closer to a situation in which the answer is known.
A case for which the answer is known (and can be
expressed without recursion) is called a base case.
Recursive Functions:
The General Format
if (some condition for which answer is known)
// base case
solution statement
2
Recursion Types
There are three types of recursion, depending on the
number of recursive calls in a function:
Linear Recursion
Binary Recursion
Multiple Recursion
1. Linear Recursion
Test for base cases
Begin by testing for a set of base cases (there should be at least one).
Every possible chain of recursive calls must eventually reach a base
case, and the handling of each base case should not use recursion.
Recur once
Perform a single recursive call.
There may be a test that decides which of several possible recursive
calls to make, but should ultimately make just one of these calls.
Define each possible recursive call so that it makes progress towards
a base case.
3
Example 1:
The Factorial of n – Iterative Definition
1, if n=0
n! =
n * (n-1) * … * 2 * 1, if n>0
Example 1:
The Factorial of n – Recursive Definition
1, if n=0
n! =
n * (n-1)! , if n>0
4
Writing a Recursive Function for
the Factorial of n
The function call factorial(4) should have value
24, because that is 4 * 3 * 2 * 1 .
if ( number == 0 )
return 1;
9
or, n * factorial(n - 1)
10
5
Example 1:
The Recursive Factorial Function
// Pre: number is assigned and number >= 0.
//
public int factorial ( int n ) {
if ( n == 0) // base case
return 1;
else // general case
return n * factorial ( n - 1 );
}
Performance: O (n).
11
Recursive Solution
Example:
12
6
Three-Question Method for
Verifying Recursive Functions
Base-Case Question: Is there a non-recursive way out of
the function?
13
Example 2:
Where Recursion Comes Naturally
From mathematics, we know that:
20 = 1 and 25 = 2 * 24
In general,
x0 = 1 and xn = x * xn-1
for integer x, and integer n > 0.
14
7
Example 2:
The Recursive Power Function
// Pre: n >= 0. x, n are not both zero
// Post: Function value = x raised to the power n.
//
public int power ( int x, int n ) {
if ( n == 0 )
return 1; // base case
else // general case
return ( x * power ( x , n-1 ) );
}
Performance: O (n).
Of course, an alternative would have been to use looping
instead of a recursive call in the function body.
15
1 if x = 0
p (x , n ) = x ⋅ p (x , (n − 1) / 2) 2 if x > 0 is odd
p (x , n / 2) 2 if x > 0 is even
For example,
24 = (24/2)2 = (22)2 = 42 = 16
25 = 2(24/2)2 = 2(22)2 = 2
2(4 ) = 32
26 = (26/2)2 = (23)2 = 82 = 64
27 = 2(26/2)2 = 2(23)2 = 2
2(8 ) = 128
16
8
Example 3:
Recursive Squaring Algorithm
// Pre: n >= 0. x, n are not both zero
// Post: Function value = x raised to the power n.
//
public int power ( int x, int n ) {
if ( n == 0 ) // base case
return 1;
if ( n%2 == 1 ) { // general case 1
y = Power (x, (n - 1)/ 2);
return x * y * y;
}
else { // general case 2
y = Power (x, n/ 2);
return y * y;
}
}
17
Example 3:
Recursive Squaring Analysis
// Pre: n >= 0. x, n are not both zero
// Post: Function value = x raised to the power n.
//
public int power ( int x, int n ) { Each time we make a
if ( n == 0 ) // base case recursive call we halve
return 1; the value of n; hence, we
if ( n%2 == 1 ) { // n is odd make log n recursive calls.
y = Power (x, (n - 1)/ 2); That is, this method runs
return x * y * y; in O (log n) time.
}
else { // n is even
y = Power (x, n/ 2); It is important that we
return y * y; use a variable twice here
} rather than calling the
} method twice.
18
9
Why Use Recursion?
The above examples could have been written without
recursion, using iteration instead.
19
Example 4:
A Singly Linked List
public class Node {
int info ;
Node next ;
}
public class SortedList {
private Node head ;
public
. . . // member functions
20
10
Example 4:
The ReversePrint Function
head
A B C D E
21
Example 4:
Base Case and General Case
A base case may be a solution in terms of a “smaller” list.
Certainly for a list with 0 elements, there is no more processing
to do.
22
11
Example 4:
Using Recursion with a Linked List
// Pre: listHead points to an element of a list.
// Post: all elements of list pointed to by listHead have been printed
// out in reverse order.
public void reversePrint ( Node listHead ) {
}
// Base case : if the list is empty, do nothing
}
23
What Happens
When a Function is Called?
A transfer of control occurs from the calling block to the
code of the function.
24
12
The Stack Activation Frames
The activation record stores:
• The return address for this function call
• The parameters
• The local variables
• The function’s return value, if non-void.
25
Example 5:
Another Recursive Function
// Pre: a and b have been assigned values
// Post: function value = ??
//
public int func ( int a, int b ) {
int result;
if ( b == 0 ) // base case
result = 0;
else if ( b > 0 ) // first general case
result = a + func ( a , b - 1 ) ) ; // instruction 50
else // second general case
result = func ( - a , - b ) ; // instruction 70
return result;
}
26
13
Run-Time Stack Activation Records
x = func(5, 2); // original call is instruction 100
functionVAL ?
result ? original call
b 2 at instruction 100
a 5 pushes on this record
Return Address 100 for func(5,2)
27
14
Run-Time Stack Activation Records
x = func(5, 2); // original call is instruction 100
fubctionVAL ? call in func(5,1) code
result ? at instruction 50
b 0 pushes on this record
a 5 for func(5,0)
Return Address 50
functionVAL ?
result 5+func(5,0) = ?
b 1
a 5 record for func(5,1)
Return Address 50
functionVAL ?
result 5+func(5,1) = ?
b 2
a 5 record for func(5,2)
Return Address 100
29
15
Run-Time Stack Activation Records
x = func(5, 2); // original call is instruction 100
fnctionVAL 5
result 5+func(5,0) = 5+ 0
b 1
a 5 record for func(5,1)
Return Address 50 is popped next
with its functionVAL
functionVAL ?
result 5+func(5,1) = ?
b 2
a 5 record for func(5,2)
Return Address 100
31
functionVAL 10
result 5+func(5,1) = 5+5 record for func(5,2)
b 2 is popped last
a 5
with its functionVAL
Return Address 100
32
16
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
33
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
34
17
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
35
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
36
18
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
37
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
38
19
Example 6:
The Binary Search Function
Given a sorted list of n items and the key of an item, (Mustafa), find that
item’s position in the list.
The function binarySearch:
Assume the list is in array called data of size n,
public int binarySearch(E target, int first, int size) {
int middle; Position Key
39
2. Binary Recursion
Binary recursion occurs whenever there are two recursive calls
for each non-base case.
40
20
Recursion Efficiency,
Example 7: Fibonacci Numbers
Fibonacci numbers are defined by the recurrence relation:
F0 = 0,
F1 = 1,
Fn = Fn-1 + Fn-2 for n >= 2.
41
Example 7:
The Recursive Fibonacci Method
// BinaryFib: recursive version
// Pre: The parameter n is a nonnegative integer.
// Post: The function returns the nth fibonacci number.
//
public int BinaryFib (int n) {
if (n <= 0) return 0; // The basic case
else if (n == 1) return 1; // Another basic case
else return BinaryFib(n-1) + BinaryFib(n-2);
}
42
21
Analysis of Recursive Fibonacci
Let kn be the number of calls to BinaryFib, then:
• k0 = 1 and k1 = 1
• k2 = 1 + k1 + k0 =1+1+1=3
• k3 = 1 + k2 + k1 =1+3+1=5
• k4 = 1 + k3 + k2 =1+5+3=9
• k5 = 1 + k4 + k3 = 1 + 9 + 5 = 15
• k6 = 1 + k5 + k4 = 1 + 15 + 9 = 25
• k7 = 1 + k6 + k5 = 1 + 25 + 15 = 41
• k8 = 1 + k7 + k6 = 1 + 41 + 25 = 67.
Note that kn more than doubles every two consecutive ns.
That is, kn > 2n/2. It is exponential!
43
We need 20 add
operations.
O(1.7n)
44
22
A Much Better
Recursive Fibonacci Algorithm
Use linear recursion instead:
// LinearFib: Linear recursive version
// Pre: The parameter n is a nonnegative integer.
// Post: Returns a pair of fibonacci numbers (Fn , Fn-1).
//
public long[ ] LinearFib (int n) {
if ( n <= 1 ) {
long[ ] answer = {n, 0};
return answer;
}
else {
long[ ] temp = LinearFib (n - 1);
long[ ] answer = {temp[0] + temp[1], temp[0]};
return answer;
}
}
LinearFib makes n-1 recursive calls – O (n).
45
Fibonacci Numbers
A Non-Recursive Version
// fibonacci: iterative version
// Pre: The parameter n is a nonnegative integer.
// Post: The function returns the nth fibonacci number.
//
public int fibonacci (int n) {
int last_but_one; // second previous Fibonacci number, Fi-2
int last_value; // previous Fibonacci number, Fi-1
int current; // current Fibonacci number Fi
46
23
Fibonacci Numbers
A Non-Recursive Function
else {
last_but_one = 0;
last_value = 1;
Fibonacci Numbers
Non-Recursive Function efficiency
The number of operations needed to calculate F7
can be counted from the algorithm.
O(n)
48
24
3. Multiple Recursion
Where a method may make more than two
recursive calls.
• makes potentially many recursive calls
• not just one or two
Example:
Read the recursive method for analyzing the disk
space usage of a file system in Section 5.1.4) of
the textbook.
49
Efficiency of Recursion
Recursion is not efficient because:
• It may involve much more operations than necessary.
Time complexity.
• It uses the run-time stack, which involves pushing and popping a
lot of data in and out of the stack, some of it may be unnecessary.
Time and Space complexity.
25
Comments on Recursion
There are several common applications of recursion
where a corresponding iterative solution may not be
obvious or easy to develop.
51
Tail Recursion
The case in which a function contains only a
single recursive call and it is the last statement
to be executed in the function.
52
26
Example 8:
Reversing an Array Recursively
Algorithm reverseArray(A, i, j):
Input: An array A and nonnegative integer indices i and j
Output: Reversal of the elements in A between indices i & j inclusive.
if i < j then
Swap A[ i ] and A[ j ]
reverseArray(A, i + 1, j - 1)
return
This algorithm is tail recursive because:
1. It is of the linear recursive type,
2. The recursive call is at the last statement.
53
Example 8:
Removing Tail Recursion
Tail recursive methods can be easily converted to non-
recursive methods (which saves on some resources).
The reverseArray algorithm can be written as:
Algorithm iterativeReverseArray(A, i, j):
Input: An array A and nonnegative integer indices i and j
Output: Reversal of the elements in A between indices i & j inclusive.
while i < j do
Swap A[ i ] and A[ j ]
i =i+1
j =j–1
return
54
27
Conclusion:
Use a Recursive Solution when:
The depth of recursive calls is relatively “shallow”
compared to the size of the problem. (factorial is deep)
55
Example 9:
The Towers of Hanoi Problem
A B C
The Problem:
You have n disks, as shown,
and you need to move them
from tower A to tower C using tower B as temporary.
i.e. moveDisks (n,A,C,B)
The Rules:
Move only one disk at a time
No larger disk can be on top of a smaller disk
56
28
Attempted Solution
For n=1:
A B C
57
Attempted Solution
For n=1:
• move (A,C)
A B C
58
29
Attempted Solution
For n=2:
A B C
59
Attempted Solution
For n=2:
• move (A,B)
A B C
60
30
Attempted Solution
For n=2:
• move (A,B)
• move (A,C)
A B C
61
Attempted Solution
For n=2:
• move (A,B)
• move (A,C)
• move (B,C)
A B C
62
31
Attempted Solution
For n=3:
A B C
63
Attempted Solution
For n=3:
• move (A,C)
A B C
64
32
Attempted Solution
For n=3:
• move (A,C)
• move (A,B)
A B C
65
Attempted Solution
For n=3:
• move (A,C)
• move (A,B)
• move (C,B)
A B C
66
33
Attempted Solution
For n=3:
• move (A,C) Effectively, we moved 2 disks
• move (A,B) from A to B using C as temporary.
• move (C,B) i.e. moveDisks (2,A,B,C)
A B C
67
Attempted Solution
For n=3:
• move (A,C) Effectively, we moved 2 disks
• move (A,B) from A to B using C as temporary.
• move (C,B) i.e. moveDisks (2,A,B,C)
• move (A,C)
A B C
68
34
Attempted Solution
For n=3:
• moveDisks (2,A,B,C) Moved n-1 disks from A to B; temp C.
• move (A,C) Moved one disk from A to C,
this is the basic case
A B C
69
Attempted Solution
For n=3:
• moveDisks (2,A,B,C) Moved n-1 disks from A to B; temp C.
• move (A,C) Moved one disk from A to C.
• move (B,A)
A B C
70
35
Attempted Solution
For n=3:
• moveDisks (2,A,B,C) Moved n-1 disks from A to B; temp C.
• move (A,C) Moved one disk from A to C.
• move (B,A)
• move (B,C)
A B C
71
Attempted Solution
For n=3:
• moveDisks (2,A,B,C) Moved n-1 disks from A to B; temp C.
• move (A,C) Moved one disk from A to C.
• move (B,A)
• move (B,C)
A B C
• move (A,C)
72
36
Attempted Solution
For n=3:
• moveDisks (2,A,B,C) Moved n-1 disks from A to B; temp C.
• move (A,C) Moved one disk from A to C.
• move (B,A) Moved n-1 disks from B to C; temp A.
• move (B,C)
A B C
• move (A,C)
73
Attempted Solution
For n=3:
• moveDisks (2,A,B,C) Moved n-1 disks from A to B; temp C.
• move (A,C) Moved one disk from A to C.
• moveDisks (2,B,C,A) Moved n-1 disks from B to C; temp A.
A B C
74
37
Recursive Function for Solving the
Towers of Hanoi Problem – O(2n)
public static void moveDisks(int n, char s, char d, char t) {
if (n <= 1) { // base case
[Link]("Move the top disk from “);
[Link](s + " to " + d);
}
else { // general case
moveDisks(n-1, s, t, d);
moveDisks(1, s, d, t);
moveDisks(n-1, t, d, s);
}
}
75
38