The art of solving a problem by solving a smaller version of the same problem β until the answer is obvious.
Recursion is a programming technique where a method calls itself to solve a problem by breaking it down into smaller sub-problems of the same type, until it reaches a trivially simple case (the base case).
The general rule β the function calls itself with a smaller/simpler input. Progress toward the base case must be guaranteed.
The simplest input where the answer is known directly β NO recursive call. Without this, recursion never stops (infinite loop / stack overflow).
Each recursive call returns a value. The caller combines these returned values to build the final answer.
Every recursive method MUST have at least one base case. Without a base case, the method will call itself indefinitely, causing a StackOverflowError (infinite recursion). Always identify the base case first before writing any recursive method.
Each call to a method pushes a new stack frame onto the call stack. The frame stores local variables and where to return when done. Frames are popped (removed) as each call returns.
CALLING PHASE (frames pushed) β
RETURNING PHASE (frames popped) β
| Property | Recursion | Iteration |
|---|---|---|
| Mechanism | Function calls itself | Loop (for/while) |
| Termination | Base case | Loop condition |
| Memory | Stack frame per call (more) | Constant extra memory |
| Code clarity | Often elegant/compact | Can be more verbose |
| Best for | Trees, divide-&-conquer, Hanoi | Simple loops, counters |
| Risk | Stack overflow if no base case | Infinite loop |
No base case means the method calls itself forever. Java will throw a StackOverflowError when the call stack runs out of memory.
factorial(4)
= 4 Γ factorial(3)
= 3 Γ factorial(2)
= 2 Γ factorial(1)
= 1 Γ factorial(0)
= 1 β BASE CASE returns 1
= 1 Γ 1 = 1 β factorial(1) returns 1
= 2 Γ 1 = 2 β factorial(2) returns 2
= 3 Γ 2 = 6 β factorial(3) returns 6
= 4 Γ 6 = 24 β factorial(4) returns 24
n = 0 β return 1
n = 1 β return 1
(Both are needed since 0! = 1 and 1! = 1)
n > 1 β return n * factorial(n β 1)
Each call reduces n by 1, guaranteed to reach base case.
| n | n! | Recursive call |
|---|---|---|
| 0 | 1 | Base case |
| 1 | 1 | 1 Γ 0! = 1Γ1 |
| 2 | 2 | 2 Γ 1! = 2Γ1 |
| 3 | 6 | 3 Γ 2! = 3Γ2 |
| 4 | 24 | 4 Γ 3! = 4Γ6 |
| 5 | 120 | 5 Γ 4! = 5Γ24 |
| 6 | 720 | 6 Γ 5! = 6Γ120 |
| 10 | 3,628,800 | 10 Γ 9! |
The GCD (Greatest Common Divisor) of two integers is the largest positive integer that divides both without remainder. Euclid's algorithm computes it elegantly using recursion.
The key insight: any divisor of both a and b also divides (a mod b). So gcd(a, b) = gcd(b, a mod b). Eventually b becomes 0, and gcd(a, 0) = a since a divides itself and divides 0. The value of b strictly decreases with each step (a mod b < b always), guaranteeing termination.
gcd(48, 18)
β 48 mod 18 = 12 β gcd(18, 12)
β 18 mod 12 = 6 β gcd(12, 6)
β 12 mod 6 = 0 β gcd(6, 0)
β b=0, return 6 β BASE CASE
β return 6
β return 6
β return 6
β΄ GCD(48, 18) = 6 β (verify: 48Γ·6=8 β, 18Γ·6=3 β)
Binary search finds a target element in a sorted array by repeatedly halving the search space. Each recursive call searches half the remaining elements β making it O(log n).
Array: [5, 10, 15, 20, 23, 30, 42, 55, 60] (indices 0β8)
Call 1: low=0, high=8, mid=4 β arr[4]=23 β FOUND! return 4 β BASE CASE
(Lucky! Found in first call. Let's trace searching for 42:)
Call 1: low=0, high=8, mid=4 β arr[4]=23 < 42 β search RIGHT
Call 2: low=5, high=8, mid=6 β arr[6]=42 == 42 β FOUND! return 6 β BASE CASE
(Now trace for 10:)
Call 1: low=0, high=8, mid=4 β arr[4]=23 > 10 β search LEFT
Call 2: low=0, high=3, mid=1 β arr[1]=10 == 10 β FOUND! return 1 β BASE CASE
(Trace for 99 β not in array:)
Call 1: low=0, high=8, mid=4 β arr[4]=23 < 99 β search RIGHT
Call 2: low=5, high=8, mid=6 β arr[6]=42 < 99 β search RIGHT
Call 3: low=7, high=8, mid=7 β arr[7]=55 < 99 β search RIGHT
Call 4: low=8, high=8, mid=8 β arr[8]=60 < 99 β search RIGHT
Call 5: low=9, high=8 β low > high β return -1 β BASE CASE (NOT FOUND)
Array MUST be sorted in ascending order. Binary search does NOT work on unsorted arrays.
With each call, the search space is halved. So at most βlogβ nβ + 1 calls. For n=1000, only ~10 calls!
Recursion provides an elegant way to convert a decimal number to any other base (binary, octal, hexadecimal, etc.). The key insight: digits are extracted in reverse order through repeated division β recursion naturally reverses them!
When converting decimal to binary, we divide by 2 and collect remainders. But the remainders must be printed in reverse (last remainder = most significant bit). Recursion handles this naturally β it goes deep first (smaller numbers), then prints on the way back up.
convert(13, 2):
13 != 0 β call convert(13/2=6, 2)
convert(6, 2):
6 != 0 β call convert(6/2=3, 2)
convert(3, 2):
3 != 0 β call convert(3/2=1, 2)
convert(1, 2):
1 != 0 β call convert(1/2=0, 2)
convert(0, 2):
n==0 β BASE CASE: return (print nothing)
β back: print 1%2 = 1 β output so far: "1"
β back: print 3%2 = 1 β output so far: "11"
β back: print 6%2 = 0 β output so far: "110"
β back: print 13%2 = 1 β output so far: "1101"
Result: 13 in binary = 1101 β (verify: 8+4+0+1 = 13 β)
| Decimal | Binary (base 2) | Octal (base 8) | Hex (base 16) |
|---|---|---|---|
| 5 | 101 | 5 | 5 |
| 10 | 1010 | 12 | A |
| 13 | 1101 | 15 | D |
| 16 | 10000 | 20 | 10 |
| 25 | 11001 | 31 | 19 |
| 255 | 11111111 | 377 | FF |
The Tower of Hanoi is the most celebrated example of recursion. A problem that seems impossibly complex has a breathtakingly simple recursive solution β 3 lines of meaningful code!
To move n disks from A to C:
1. Move the top (nβ1) disks from A to B (using C as auxiliary)
2. Move the largest disk from A to C (just one move!)
3. Move the (nβ1) disks from B to C (using A as auxiliary)
This is exact recursion! Steps 1 and 3 are the same problem with nβ1 disks. Step 2 is the base case when n=1 (just move the single disk directly).
hanoi(3, A, C, B):
Step 1: hanoi(2, A, B, C) β move top 2 disks AβB
Step 1a: hanoi(1, A, C, B)
β Move disk 1 from A to C [Move 1]
Step 2a: Move disk 2 from A to B [Move 2]
Step 3a: hanoi(1, C, B, A)
β Move disk 1 from C to B [Move 3]
Step 2: Move disk 3 from A to C [Move 4] β the largest disk
Step 3: hanoi(2, B, C, A) β move top 2 disks BβC
Step 1b: hanoi(1, B, A, C)
β Move disk 1 from B to A [Move 5]
Step 2b: Move disk 2 from B to C [Move 6]
Step 3b: hanoi(1, A, C, B)
β Move disk 1 from A to C [Move 7]
Total moves for n=3: 7 moves (= 2Β³ - 1 = 7 β)
| n disks | Moves = 2βΏ β 1 | If 1 move/sec |
|---|---|---|
| 1 | 1 | 1 second |
| 2 | 3 | 3 seconds |
| 3 | 7 | 7 seconds |
| 4 | 15 | 15 seconds |
| 10 | 1,023 | ~17 minutes |
| 64 | 18,446,744,073,709,551,615 | ~585 billion years! |
Calling phase: Method calls are made, parameters change, stack grows
Returning phase: Results are computed and returned, stack shrinks
Indentation shows depth β deeper = further down the call stack
| Algorithm | Base Case(s) | Recursive Case | Time Complexity | Calls for n=5 |
|---|---|---|---|---|
| Factorial | n = 0 or 1 | n * fact(n-1) | O(n) | 5 |
| GCD(a,b) | b = 0 | gcd(b, a%b) | O(log min(a,b)) | varies |
| Binary Search | low>high OR found | search half | O(log n) | ~3 |
| Base Conversion | n = 0 | conv(n/base) | O(log n) | varies |
| Tower of Hanoi | n = 1 | 2 Γ hanoi(n-1) | O(2βΏ) | 31 |
1. Write a recursive method to find the factorial of n. Trace it for n=4.
2. Write a recursive method to find GCD(a, b). Trace gcd(36, 24).
3. Explain the base case and recursive case of binary search.
4. Write a recursive method to convert a decimal number to binary.
5. Write a recursive method for Tower of Hanoi. How many moves for n disks?
6. What is infinite recursion? How can it be avoided?
7. Explain the call stack with reference to a recursive method.
8. Trace binary search on a sorted array for a given key.