Neural Sync Active
Week 9: Recursion
Registry Synced
Week 9: Recursion
1560 words
8 min read
Reading compass
Now · 1. Motivation: Why Recursion?
Week 9: Recursion
BSCS1001 — IIT Madras BS Degree Prerequisite: Week 3 (Procedures), Week 5 (Lists) Cross-links: BSCS1002-Python (Week 10 — Recursion), BSCS2002-PDSA (Week 9 — Recursion)
1. Motivation: Why Recursion?
Some problems have a natural structure where the solution to a big problem depends on solving a smaller version of the same problem.
| Problem | Big Version | Smaller Version |
|---|---|---|
| Factorial | 5! = 5 × 4 × 3 × 2 × 1 | 4! = 4 × 3 × 2 × 1 |
| Sum of list | [1,2,3] sum = 1 + rest | [2,3] sum |
| DFS on graph | Explore all neighbors | Explore one neighbor's neighbors |
| Insertion sort | Sort N elements | Sort N-1 elements, then insert last |
Real-world analogy: Russian nesting dolls (matryoshka). To open the largest doll, you recursively open smaller and smaller dolls until you reach the smallest one, then build back up.
2. What is Recursion?
Recursion is when a procedure calls itself.
(Diagram)
Two Essential Parts
Every recursive procedure must have:
- Base case: A simple version that can be solved directly (no recursion)
- Recursive case: A version that calls itself with smaller input
💡 Key Insight: If there's no base case, the recursion never stops (infinite recursion). If the recursive case doesn't reduce the problem size, it also never stops.
3. Anatomy of a Recursive Procedure
Template
pseudoProcedure RecursiveFunction(input) // Base case if (base condition) { return(simple value) } // Recursive case else { smallerInput = reduce(input) partialResult = RecursiveFunction(smallerInput) result = combine(partialResult, input) return(result) } End RecursiveFunction
The Three Questions
| Question | Answer | Example (Factorial) |
|---|---|---|
| What is the base case? | Smallest input we can solve directly | n = 0 |
| What is the base value? | Answer for base case | 1 |
| How do we reduce? | Make input smaller | n → n-1 |
| How do we combine? | Use result of smaller to solve larger | n × factorial(n-1) |
4. Factorial: The Classic Example
Mathematical Definition
pseudon! = n × (n-1) × (n-2) × ... × 2 × 1 0! = 1 (by definition)
Recursive Definition
pseudofactorial(0) = 1 // Base case factorial(n) = n × factorial(n-1) // Recursive case (for n > 0)
Pseudocode
pseudoProcedure Factorial(n) if (n == 0) { return(1) } else { return(n * Factorial(n-1)) } End Factorial
Tracing Factorial(4)
(Diagram)
Tracing Table
| Call | Input | Checks Base? | Recursive Call | Returns |
|---|---|---|---|---|
| Factorial(4) | 4 | No (4≠0) | 4 × Factorial(3) | 4 × 6 = 24 |
| Factorial(3) | 3 | No | 3 × Factorial(2) | 3 × 2 = 6 |
| Factorial(2) | 2 | No | 2 × Factorial(1) | 2 × 1 = 2 |
| Factorial(1) | 1 | No | 1 × Factorial(0) | 1 × 1 = 1 |
| Factorial(0) | 0 | Yes! | (none) | 1 |
5. Tracing Recursion: The Call Stack
What Happens in Memory
When
Factorial(4) calls Factorial(3), the computer:- Suspends
Factorial(4)— remembers where it was and its variables - Starts
Factorial(3)on top of it - This continues until
Factorial(0)returns - Then each suspended call resumes in reverse order
The Call Stack
sqlStep 1: Factorial(4) called Stack: [Factorial(4)] Step 2: Factorial(4) calls Factorial(3) Stack: [Factorial(4), Factorial(3)] Step 3: Factorial(3) calls Factorial(2) Stack: [Factorial(4), Factorial(3), Factorial(2)] Step 4: Factorial(2) calls Factorial(1) Stack: [..., Factorial(2), Factorial(1)] Step 5: Factorial(1) calls Factorial(0) Stack: [..., Factorial(1), Factorial(0)] Step 6: Factorial(0) returns 1 — POPS from stack Stack: [..., Factorial(1)] Step 7: Factorial(1) computes 1*1 = 1 — POPS Stack: [..., Factorial(2)] Step 8: Factorial(2) computes 2*1 = 2 — POPS Stack: [..., Factorial(3)] Step 9: Factorial(3) computes 3*2 = 6 — POPS Stack: [Factorial(4)] Step 10: Factorial(4) computes 4*6 = 24 — POPS Stack: [] (empty)
6. Recursion on Lists
Sum of List Elements
pseudoProcedure ListSum(L) if (L == []) { return(0) // Base: empty list sum = 0 } else { return(first(L) + ListSum(rest(L))) // First + sum of rest } End ListSum
Tracing: ListSum([1, 3, 5])
| Call | L | Base? | first(L) + ListSum(rest) | Result |
|---|---|---|---|---|
| ListSum([1,3,5]) | [1,3,5] | No | 1 + ListSum([3,5]) | 1+8=9 |
| ListSum([3,5]) | [3,5] | No | 3 + ListSum([5]) | 3+5=8 |
| ListSum([5]) | [5] | No | 5 + ListSum([]) | 5+0=5 |
| ListSum([]) | [] | Yes | 0 (base) | 0 |
Length of List
pseudoProcedure ListLength(L) if (L == []) { return(0) } else { return(1 + ListLength(rest(L))) } End ListLength
7. Recursive Insertion Sort
Insertion sort can be defined recursively:
Recursive Definition
- Base case: A list of length ≤ 1 is already sorted
- Recursive case: Sort
rest(L), then insertfirst(L)into the sorted rest
Pseudocode
pseudoProcedure InsertionSortRec(L) if (length(L) <= 1) { return(L) } else { sortedRest = InsertionSortRec(rest(L)) return(SortedListInsert(sortedRest, first(L))) } End InsertionSortRec
Tracing: InsertionSortRec([3, 1, 4])
| Call | L | Base? | sortedRest | Insert first(L) into sortedRest | Result |
|---|---|---|---|---|---|
| ISR([3,1,4]) | [3,1,4] | No | ISR([1,4]) → [1,4] | Insert 3 → [1,3,4] | [1,3,4] |
| ISR([1,4]) | [1,4] | No | ISR([4]) → [4] | Insert 1 → [1,4] | [1,4] |
| ISR([4]) | [4] | Yes | — | — | [4] |
8. Recursion vs Iteration
| Aspect | Iteration | Recursion |
|---|---|---|
| Mechanism | Loop (while, foreach) | Self-calling procedure |
| State | Explicit variables | Implicit (call stack) |
| Termination | Condition becomes false | Base case reached |
| Performance | Generally faster | Slightly slower (call overhead) |
| Memory | Less (fixed variables) | More (call stack grows) |
| Natural for | Sequential processing | Hierarchical/inductive problems |
| Risk | Infinite loop | Stack overflow (infinite recursion) |
When to Use Recursion
(Diagram)
9. Practice Questions
Basic Questions
Q1. What are the two essential parts of a recursive procedure?
Show Answer
Base case: A simple input that can be solved directly (no recursion) Recursive case: Calls itself with a smaller/ simpler input Q2. Trace Factorial(3) showing all recursive calls and returns. Show Answer
| Call | n | Base? | Action | Returns |
|---|---|---|---|---|
| Factorial(3) | 3 | No | 3 × Factorial(2) | 6 |
| Factorial(2) | 2 | No | 2 × Factorial(1) | 2 |
| Factorial(1) | 1 | No | 1 × Factorial(0) | 1 |
| Factorial(0) | 0 | Yes | Return 1 | 1 |
Final result: 6 Q3. Write a recursive procedure to compute the sum of integers from 1 to n. Show AnswerpseudoProcedure SumToN(n) if (n == 0) { return(0) } else { return(n + SumToN(n-1)) } End SumToN
Q4. What happens if a recursive procedure has no base case?
Show AnswerIt results in infinite recursion — the procedure calls itself forever, never returning. This would eventually cause a stack overflow (the call stack runs out of memory).
Intermediate Questions
Q5. Trace ListLength([10, 20, 30, 40]).
Show Answer
| Call | L | Base? | Returns |
|---|---|---|---|
| LL([10,20,30,40]) | [10,20,30,40] | No | 1 + LL([20,30,40]) = 4 |
| LL([20,30,40]) | [20,30,40] | No | 1 + LL([30,40]) = 3 |
| LL([30,40]) | [30,40] | No | 1 + LL([40]) = 2 |
| LL([40]) | [40] | No | 1 + LL([]) = 1 |
| LL([]) | [] | Yes | 0 |
Final result: 4 Q6. Write a recursive procedure to find the maximum element in a list. Show AnswerpseudoProcedure MaxList(L) if (length(L) == 1) { return(first(L)) // Only one element } else { maxOfRest = MaxList(rest(L)) if (first(L) > maxOfRest) { return(first(L)) } else { return(maxOfRest) } } End MaxList
Q7. Compare recursion and iteration. Give one advantage of each.
Show Answer
- Advantage of recursion: More natural for problems with self-similar structure (factorial, tree traversal, DFS). Code is often more elegant and readable.
- Advantage of iteration: Generally faster, uses less memory (no call stack), and is simpler for straightforward repetitive tasks.
Trade-off: Elegance vs efficiency. Q8. What is the call stack? Why is it important for recursion? Show AnswerThe call stack is a data structure that tracks all active (suspended) procedure calls. When a procedure calls another, the current state is pushed onto the stack. When the called procedure returns, the previous state is popped.For recursion, the call stack is essential because each recursive call suspends the current computation. Without it, the computer couldn't "remember" where to resume after the recursive call returns.
Advanced Questions
Q9. Trace the recursive insertion sort for [4, 2, 5].
Show Answer
| Call | L | Base? | sortedRest | Insert first | Result |
|---|---|---|---|---|---|
| ISR([4,2,5]) | [4,2,5] | No | [2,4,5] | Insert 4 → [2,4,5] | [2,4,5] |
| ISR([2,5]) | [2,5] | No | [5] | Insert 2 → [2,5] | [2,5] |
| ISR([5]) | [5] | Yes | — | — | [5] |
Final: [2, 4, 5] Q10. Write a recursive procedure to check if a value x is present in a list. Show AnswerpseudoProcedure IsMember(x, L) if (L == []) { return(False) // Not found } else if (first(L) == x) { return(True) // Found! } else { return(IsMember(x, rest(L))) // Search rest } End IsMember
Q11. Why does the recursive case need to reduce the problem size? What happens if it doesn't?
Show AnswerThe recursive case MUST reduce the problem size (move toward the base case) to ensure termination. If it doesn't:
- The procedure would call itself with the same (or larger) input forever
- The base case would never be reached
- This results in infinite recursion → stack overflow
Example of WRONG factorial:pseudoProcedure BadFactorial(n) if (n == 0) { return(1) } else { return(n * BadFactorial(n)) // n doesn't decrease! } End BadFactorialThis never reaches n=0 and runs forever. Q12. A recursive procedure has a "premature" base case. What would happen if Factorial's base case was n=1 instead of n=0? Show AnswerIfFactorial(0)is called:
- Base case is n=1 → not reached
- Recursive case: n=0 → calls Factorial(-1)
- Factorial(-1): calls Factorial(-2)
- ... never reaches 1, runs forever
The original definition with base case n=0 is correct because factorials are defined for non-negative integers, and 0! = 1.
📚 Cross-References
| Course | Topic | Connection |
|---|---|---|
| BSCS1002 (Python) | Week 10 — Recursion | Python recursive functions |
| BSCS2002 (PDSA) | Week 9 — Recursion | Recursion tree, tail recursion |
| BSCS2002 (PDSA) | Week 10 — Divide & Conquer | Recursive problem solving |
Next Topic: 16 — Depth-First SearchQuiz Tip: Recursion tracing questions are common. Practice drawing the call stack! Join Discord PreviousGraph Algorithms — Routes & PathsNextDepth-First Search (DFS)