Recursion
Recursion is a programming technique in which
a method calls itself to fulfill its purpose.
In some situations, a recursive method definition
is an appropriate way to solve a problem.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 1
Outline
Recursive Factorial and the Runtime Stack
Characteristics of Recursion
Thinking Recursively and Helper Methods
Implementing Binary Search with Recursion
Solving the Tower of Hanoi with Recursion
Getting the Directory Size with Recursion
Dr. Muhamed Mudawar Computer Science II Recursion – slide 2
Recursive Factorial
n! = n × (n – 1) × (n – 2) × . . . × 1
n! = n × (n – 1)! Recursive definition
0! = 1 Base case
factorial(n) = n * factorial(n-1);
factorial(0) = 1;
We can write a recursive method to compute the factorial
Dr. Muhamed Mudawar Computer Science II Recursion – slide 3
Recursive Factorial Method
import java.util.Scanner;
public class ComputeFactorial {
ComputeFactorial
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter a non-negative integer: ");
int n = input.nextInt();
System.out.println("Factorial of " + n + " is " + factorial(n));
}
// Computes and returns the factorial recursively
public static long factorial(int n) {
if (n == 0) return 1; // Base case
return n * factorial(n - 1); // Recursive call
}
}
Dr. Muhamed Mudawar Computer Science II Recursion – slide 4
Computing the Recursive Factorial
factorial(4) = 4 * factorial(3) factorial(n) = n*factorial(n-1);
= 4 * (3 * factorial(2))
= 4 * (3 * (2 * factorial(1)))
= 4 * (3 * ( 2 * (1 * factorial(0)))) factorial(0) = 1;
= 4 * (3 * ( 2 * ( 1 * 1))))
= 4 * (3 * ( 2 * 1))
= 4 * (3 * 2)
= 4 * (6)
= 24
Dr. Muhamed Mudawar Computer Science II Recursion – slide 5
Tracing the Recursive Calls
Dr. Muhamed Mudawar Computer Science II Recursion – slide 6
The Runtime Stack
The runtime stack is used to implement methods and
recursive calls.
The runtime stack is used to allocate space for the
parameters and local variables that are used in the method.
Each call to factorial(n) has its copy of the parameter n
and its space on the runtime stack.
The stack grows when there is a call to a method.
The stack shrinks when a method returns to its caller.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 7
Tracing Calls on the Runtime Stack
Each call to Runtime
factorial(n) Stack
allocates space on factorial(0), n = 0
Recursive Call
the runtime stack factorial(1), n = 1
and has its copy of Recursive Call
factorial(2), n = 2
the parameter n. Recursive Call
factorial(3), n = 3
The stack grows Recursive Call
factorial(4), n = 4
when there is a call Call
main method
to a method.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 8
Tracing Returns on the Runtime Stack
Each return from Runtime
factorial(n) Stack
returns a result to its factorial(0), n = 0
Return 1
caller and frees space factorial(1), n = 1
on the runtime stack. Return 1*1
factorial(2), n = 2
Return 2*1
The stack shrinks factorial(3), n = 3
when there is a return Return 3*2 = 6
factorial(4), n = 4
from a method. Return 4*6 = 24
main method
Dr. Muhamed Mudawar Computer Science II Recursion – slide 9
Next . . .
Recursive Factorial and the Runtime Stack
Characteristics of Recursion
Thinking Recursively and Helper Methods
Implementing Binary Search with Recursion
Solving the Tower of Hanoi with Recursion
Getting the Directory Size with Recursion
Dr. Muhamed Mudawar Computer Science II Recursion – slide 10
Characteristics of Recursion
All recursive methods have the following characteristics:
One or more base cases are used to stop recursion.
Every recursive call reduces the original problem, bringing it
increasingly closer to a base case until it becomes that case.
To solve a problem recursively, divide it into subproblems.
If a subproblem resembles the original problem, you can call the
same method recursively to solve the subproblem.
The subproblem is similar to the original problem in nature, but
smaller in size.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 11
Infinite Recursion
All recursive methods must have a non-recursive part.
The non-recursive part is called the base case that terminates
the recursive calls.
A recursive method definition without a non-recursive part
causes infinite recursion.
This problem is similar to an infinite loop, because there is
no way to terminate the recursive calls.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 12
Thinking Recursively
Many problems can be solved using recursion if you think
recursively. For example, the palindrome problem can be
solved recursively as follows:
public static boolean isPalindrome(String s) {
// Base case
if (s.length() <= 1) return true;
// Base case
if (s.charAt(0) != s.charAt(s.length() - 1)) return false;
// Recursive call
return isPalindrome(s.substring(1, s.length() - 1));
}
Dr. Muhamed Mudawar Computer Science II Recursion – slide 13
Recursive Helper Method
The preceding isPalindrome method is not efficient,
because it creates a new substring for every recursive call.
To avoid creating new substrings, use a helper method:
public static boolean isPalindrome(String s) {
return isPalindrome(s, 0, s.length() - 1);
}
public static boolean isPalindrome(String s, int low, int high) {
if (low >= high) return true; // Base case
if (s.charAt(low) != s.charAt(high)) return false; // Base case
return isPalindrome(s, low+1, high-1); // Recursive call
}
Dr. Muhamed Mudawar Computer Science II Recursion – slide 14
Next . . .
Recursive Factorial and the Runtime Stack
Characteristics of Recursion
Thinking Recursively and Helper Methods
Implementing Binary Search with Recursion
Solving the Tower of Hanoi with Recursion
Getting the Directory Size with Recursion
Dr. Muhamed Mudawar Computer Science II Recursion – slide 15
Binary Search
Binary search is a fast algorithm for searching a sorted array.
The algorithm works as follows:
Search the middle element in the array
Case 1: If the target is found at the middle, the search ends with a
match and the method returns the index of the found element.
Case 2: If the target is less than the middle element, search
recursively the first half of the array.
Case 3: If the target is greater than the middle element, search
recursively the second half of the array.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 16
Recursive Binary Search
// Use binary search to find target in the array
public static int binarySearch(int[] array, int target) {
return binarySearch(array, target, 0, array.length - 1);
}
// Recursive binary search helper method RecursiveBinarySearch
public static
int binarySearch(int[] array, int target, int low, int high) {
if (low > high) return -1; // target element not found
int mid = (low + high) / 2; // middle index
if (target == array[mid]) return mid; // found at mid index
if (target < array[mid]) // search left subarray
return binarySearch(array, target, low, mid-1);
return binarySearch(array, target, mid+1, high); // right subarray
}
Dr. Muhamed Mudawar Computer Science II Recursion – slide 17
Next . . .
Recursive Factorial and the Runtime Stack
Characteristics of Recursion
Thinking Recursively and Helper Methods
Implementing Binary Search with Recursion
Solving the Tower of Hanoi with Recursion
Getting the Directory Size with Recursion
Dr. Muhamed Mudawar Computer Science II Recursion – slide 18
Tower of Hanoi
There are n disks labeled 1, 2, 3, . . . , n, and three towers
labeled A, B, and C.
All the disks are initially placed on tower A.
The goal of the Tower of Hanoi problem is to move disks
from tower A to B without breaking the rules.
Rule 1: No disk can be on top of a smaller disk at any time.
Rule 2: Only one disk can be moved at a time, and it must be
the top disk on the tower.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 19
Moving Three Disks
First, move the top two disks from tower A to C using tower
B as auxiliary.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 20
Moving Three Disks – cont'd
Move disk 3 from A to B, then move the top two disks from
C to B, using tower A as auxiliary.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 21
Recursive Solution for the Tower of Hanoi
Dr. Muhamed Mudawar Computer Science II Recursion – slide 22
Recursive Method for the Tower of Hanoi
// Recursive method for finding the solution to move n disks
// from a source tower to a target tower using auxiliary tower
public static void moveDisks (int n, char from, char to, char aux) {
if (n == 1) // Base Case, no recursive call
System.out.printf("Move disk 1 from %c to %c%n", from, to);
else {
// First recursive call to move n-1 disks
moveDisks(n−1, from, aux, to);
System.out.printf("Move disk %d from %c to %c%n", n, from, to);
// Second recursive call to move n-1 disks
moveDisks(n−1, aux, to, from);
} TowerOfHanoi
}
Dr. Muhamed Mudawar Computer Science II Recursion – slide 23
Next . . .
Recursive Factorial and the Runtime Stack
Characteristics of Recursion
Thinking Recursively and Helper Methods
Implementing Binary Search with Recursion
Solving the Tower of Hanoi with Recursion
Getting the Directory Size with Recursion
Dr. Muhamed Mudawar Computer Science II Recursion – slide 24
Directory Size
A directory may contain files and subdirectories containing
more files and subdirectories.
The size of a directory is the sum of the sizes of all files in
the directory and its subdirectories:
Dr. Muhamed Mudawar Computer Science II Recursion – slide 25
Recursive Directory Size Method
import java.io.File;
import java.util.Scanner;
public class DirectorySize {
public static void main(String[] args) {
System.out.print("Enter a directory or a file: ");
Scanner input = new Scanner(System.in);
String directory = input.nextLine();
System.out.println("Size = " + size(new File(directory)) + " bytes");
}
public static long size(File file) { // Recursive method
if (file.isFile()) return file.length(); // Base case
long size = 0; // total size of all files
File[] files = file.listFiles(); // All files and subdirectories
for (int i=0; files!=null && i<files.length; i++) size += size(files[i]);
return size;
} DirectorySize
}
Dr. Muhamed Mudawar Computer Science II Recursion – slide 26
Recursion versus Iteration
Recursion is an alternative form of program control. It is
essentially repetition without using a loop. Every recursive
solution can be converted into an iterative solution.
Recursion has some overhead. Each time the method calls
itself recursively, the system must allocate space for all its
local variables and parameters on the runtime stack.
This can consume considerable memory and requires extra
time to manage the additional space on the stack.
Use recursion for solving the problems that are inherently
recursive in nature. The recursive solution becomes simpler.
Dr. Muhamed Mudawar Computer Science II Recursion – slide 27