Recursion and Recursive Algorithms
Recursion
Process when function calls itself within its own definition/body.
Recursive algorithms are a powerful tool in computer science, allowing us to solve complex problems by breaking them down into smaller, more manageable sub-problems.
How Recursive Algorithms Work
A recursive algorithm typically consists of two main parts:
- Base Case: The simplest instance of the problem, which can be solved directly without further recursion.
- Recursive Case: The part of the algorithm where the problem is broken down into smaller sub-problems, and the algorithm calls itself to solve these sub-problems.
- Consider the problem of calculating the factorial of a number $n$, denoted as $n!$.
- A recursive algorithm for calculating the factorial can be defined as:
- Base Case: If $n = 1$, return $1$.
- Recursive Case: Otherwise, return $n \times (n-1)!$.
public class Main{
public static int factorial(int n){
System.out.println("Called factorial with n = " + n); // for tracing
if (n==1){ // base case (termination condition)
return 1;
}
return n * factorial(n-1);
}
public static void main(String[] args){
int res = factorial(5);
System.out.println("Result: " + res);
}
}
The calculation of a factorial is an algorithm with one recursive call.
Why Use Recursive Algorithms?
Recursive algorithms are particularly useful for problems that can be naturally divided into smaller sub-problems. They are often used in situations where:
- The problem has a self-similar structure, meaning it can be broken down into smaller instances of the same problem.
- The solution to the problem can be constructed from the solutions to its sub-problems.
Some common examples of problems that are well-suited for recursive algorithms include:
- Factorial Calculation: As discussed earlier, the factorial of a number can be calculated recursively.
- Fibonacci Sequence: The Fibonacci sequence is defined such that each number is the sum of the two preceding numbers. This naturally lends itself to a recursive solution.
- Tree Traversal: Traversing a tree data structure, such as a binary tree, can be done recursively by visiting each node and its children.
- Sorting Algorithms : Algorithms like merge sort and quick sort use recursion to sort arrays by dividing them into smaller sub-arrays.
Practical Constraints of Recursive Algorithms
While recursive algorithms are elegant and powerful, they come with certain constraints that must be considered:
Stack overflow
- Each recursive call adds a new frame to the call stack, which is a data structure that keeps track of active function calls.
- If the recursion is too deep, the call stack can overflow, leading to a stack overflow error.
- Calculating the factorial of a large number, such as $10000!$, using a recursive algorithm would result in 10,000 recursive calls.
- This would likely exceed the call stack limit, causing a stack overflow.