Recursive programming has a method that call itself.
However, we do not want to call the method itself recursively to infinity (infinite recursion).
The condition that leads to a recursive method returning without making another recursive call is base cases.
Every recursive method has a base case or base cases!
Bookkeeping
For a recursive method, there is a lot of bookkeeping information that needs to be stored. Here, there are five pending calls till it hits its base case.
These pending calls may be very deeply nested. All of these pending calls are pushed onto the call stack. As the call hits the base case, then there is a return value and from that point, we pop the call from the stack to calculate and return a value.
Usually, recursion is used because it simplifies a problem conceptually, not because it is more efficient.
Example 1: Fibonacci Numbers
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
public static int fib(int n) {
if (n == 1 || n == 0) return n; // base case
return fib(n - 1) + fib(n - 2); // recursive case
}
private static int find(int[] data, int key, int lowerBound, int upperBound) {
if (lowerBound > upperBound) {
return -1;
}
int mid = lowerBound + (upperBound - lowerBound) / 2;
if (data[mid] == key) {
return mid;
}
if (data[mid] < key) {
find(data, key, mid + 1, upperBound);
} else {
find(data, key, lowerBound, mid - 1);
}
}
The method calls itself over and over but, each time with a smaller range of arrays than before till it hits one of the base cases.
If we were to make this to be a public method, it would look more complicated for users to specify lowerBound and upperBound. In fact, a user of this recursive method may not know what should be initial lowerBound and upperBound values.
To remove this kind of burden or confusion from users, we can provide the following public method that has an initial call of the private helper method in it.
public static int find(int[] data, int key) {
return find(data, key, 0, data.length - 1);
}
Summary: characteristics of Recursive Methods
1. It calls itself.
2. When it calls itself, it does so to solve a smaller version of the same problem.
3. There is a base case (or base cases) that does not call itself anymore.