Recursion - Complete Interactive Lesson
Part 1: What Recursion Is
๐ Recursion
Part 1 of 7 โ What Recursion Is
Topics in This Part
| Section |
|---|
| A Method That Calls Itself |
| Base Case vs. Recursive Case |
| Why Recursion Doesn't Run Forever |
| Reading a Recursive Method |
๐ Key Concept: A recursive method is a method that calls itself to solve a smaller version of the same problem. Every recursive method needs two ingredients: a base case that stops the recursion, and a recursive case that moves toward the base case.
A Method That Calls Itself
Look at the classic example โ factorial. By definition , and . That mathematical definition translates almost word-for-word into Java:
public static int factorial(int n) {
if (n == 0) { // base case
return 1;
}
return n * factorial(n - 1); // recursive case
}
The method factorial calls itself with a smaller argument (n - 1). It keeps shrinking the problem until it reaches n == 0, where it can answer directly without recursing.
| Term | Meaning |
|---|---|
| Base case | The condition where the method returns without calling itself. It stops the recursion. |
| Recursive case | The branch where the method calls itself on a smaller / simpler input. |
โ ๏ธ Every recursive method must have at least one base case. A recursive method with no reachable base case calls itself forever and crashes with a StackOverflowError.
Concept Check ๐ฏ
Moving Toward the Base Case
A base case alone is not enough โ the recursive call must make progress toward it. In factorial, each call uses n - 1, so n marches steadily down to 0.
factorial(4)
โ 4 * factorial(3)
โ 3 * factorial(2)
โ 2 * factorial(1)
โ 1 * factorial(0)
โ 1 (base case reached!)
Now the answers flow back up: .
๐ก The two-part test for a correct recursion:
- Is there a base case that returns directly?
- Does every recursive call get closer to that base case?
If a recursive call used
n + 1or unchanged, it would never reach โ that is .
Spot the Bug ๐
Trace It ๐งฎ
Using the factorial method from this part:
1) What does factorial(3) return?
2) What does factorial(0) return?
Part 2: Tracing the Call Stack
๐ Recursion
Part 2 of 7 โ Tracing the Call Stack
๐ The Idea: When a method calls itself, each call gets its own copy of the parameters and local variables, stacked on the call stack. Calls pause "on the way down" and resume "on the way up." Tracing this is the #1 recursion skill the AP exam tests.
How the Call Stack Works
Each method call is a stack frame. A new call is pushed on top; when it returns, it is popped off and control goes back to the caller, which resumes right where it paused.
Consider:
public static int sum(int n) {
if (n <= 0) return 0; // base case
return n + sum(n - 1); // recursive case
}
Tracing sum(3):
| Step | What happens | Pending expression |
|---|---|---|
| 1 | sum(3) called | 3 + sum(2) |
| 2 | sum(2) called | 2 + sum(1) |
| 3 | sum(1) called | 1 + sum(0) |
| 4 | sum(0) โ base case | returns |
Part 3: Recursion vs. Iteration
๐ Recursion
Part 3 of 7 โ Recursion vs. Iteration
๐ The Idea: Anything you can do with a loop, you can do with recursion, and vice-versa. Recursion trades a loop variable for the call stack. Knowing how to convert between them โ and the cost of each โ is core AP CSA content.
The Same Job, Two Ways
Here is a sum from 1 to n, written iteratively and recursively:
// Iterative
public static int sumIter(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}
// Recursive
public static int sumRec(int n) {
if (n <= 0) return 0;
return n + sumRec(n - 1);
}
| Iteration (loop) | Recursion | |
|---|---|---|
| Repetition via | loop variable (i) | repeated method calls |
| State stored in | local variables | the call stack |
| Stops when | loop condition is false | base case is reached |
| Risk | infinite loop | infinite recursion / StackOverflowError |
Part 4: Recursion on Strings
๐ Recursion
Part 4 of 7 โ Recursion on Strings
๐ The Idea: Strings are a favorite AP target for recursion. The trick is to peel off one character (usually the first or last) and recurse on the rest of the string using
substring.
Peeling Off One Character
Two String methods power almost every recursive String problem:
| Method | Returns |
|---|---|
s.length() | number of characters |
s.substring(1) | everything except the first character |
s.charAt(0) | the first character |
s.substring(0, s.length()-1) | everything except the last character |
Reverse a String by moving the first character to the end of the reversed rest:
public static String reverse(String s) {
if (s.length() <= 1) return s; // base case
return reverse(s.substring(1)) + s.charAt(0);
}
Trace reverse("cat"):
reverse("cat") = reverse("at") + 'c'
reverse("at") = reverse("t") + 'a'
reverse("t") = "t" (base case, length 1)
Unwinding: reverse("t") = "t" โ reverse("at") = "t" + "a" = "ta" โ .
Part 5: Fibonacci & Multiple Recursive Calls
๐ Recursion
Part 5 of 7 โ Fibonacci & Multiple Recursive Calls
๐ The Idea: Some methods make two (or more) recursive calls. The most famous is Fibonacci, where each term is the sum of the two before it. Multiple calls cause the work to branch โ which is powerful but can be expensive.
The Fibonacci Sequence
The Fibonacci numbers are , defined by:
Part 6: Recursion on Arrays & Common Pitfalls
๐ Recursion
Part 6 of 7 โ Recursion on Arrays & Common Pitfalls
๐ The Idea: To recurse over an array, pass an index that moves toward the end (or the length toward 0). Combined with the pitfalls section, this rounds out everything the AP exam asks about recursion.
Recursing Over an Array
Unlike a String, you can't easily "chop off" an array element, so you pass an index that advances toward arr.length. Here we sum an int[] starting at index i:
public static int arraySum(int[] arr, int i) {
if (i == arr.length) return 0; // base case: past the end
return arr[i] + arraySum(arr, i + 1); // add this element, recurse
}
// Called as arraySum(arr, 0) to sum the whole array.
Trace arraySum({4, 2, 7}, 0):
arraySum(arr,0) = 4 + arraySum(arr,1)
arraySum(arr,1) = 2 + arraySum(arr,2)
arraySum(arr,2) = 7 + arraySum(arr,3)
arraySum(arr,3) = 0 (i == length, base case)
Unwinding: . The array sums to .
Part 7: Mixed Practice & Mastery Check
๐ Recursion
Part 7 of 7 โ Mixed Practice & Mastery Check
You can now (1) identify base and recursive cases, (2) trace the call stack, (3) convert between recursion and iteration, (4) recurse on Strings and arrays, and (5) reason about Fibonacci-style branching. Let's put it together.
Quick Reference
| Goal | Key move |
|---|---|
| Stop the recursion | a base case that returns without recursing |
| Make progress | each recursive call uses a smaller input (n-1, substring(1), i+1) |
| Combine results | return <something> + helper(...) โ always use the returned value |
| Top-down output | put work before the recursive call |
| Bottom-up output | put work after the recursive call |
| Recurse on an array | pass an index; base case at i == arr.length |
| Two-step definitions (Fibonacci) | needs two base cases (n==0, n==1) |
โ ๏ธ Top three mistakes: (1) no reachable base case โ StackOverflowError; (2) forgetting to / use the recursive result; (3) wrong order of work relative to the call.