Why Recursion Exists and What Loops Cannot Express Cleanly in DSA C++ - Performance Analysis
We want to see how recursive functions grow in work compared to loops.
How does recursion handle repeated tasks differently from loops?
Analyze the time complexity of this recursive factorial function.
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
This code calculates factorial by calling itself with smaller values until it reaches 1.
Look for repeated work done by the function.
- Primary operation: Recursive call to factorial with n-1
- How many times: Exactly n times until base case
Each call waits for the next smaller call, so work grows with n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 calls |
| 100 | 100 calls |
| 1000 | 1000 calls |
Pattern observation: The number of calls grows linearly as n increases.
Time Complexity: O(n)
This means the work grows in a straight line with the input size.
[X] Wrong: "Recursion always makes code slower than loops."
[OK] Correct: Recursion can express problems loops cannot easily handle, like tree traversals, and can be just as efficient.
Understanding recursion's time helps you explain why it's useful and when to choose it over loops.
"What if we changed the recursion to a loop with a stack? How would the time complexity change?"
Practice
Solution
Step 1: Understand problem structure
Some problems have parts that look like smaller versions of themselves, like trees or nested lists.Step 2: Compare recursion and loops
Loops repeat actions linearly, but recursion can call itself to handle nested or self-similar parts easily.Final Answer:
Because recursion can express problems with self-similar structure more naturally -> Option AQuick Check:
Self-similar problems naturally use recursion [OK]
- Thinking loops are always slower
- Assuming recursion always uses less memory
- Believing loops cannot repeat actions
Solution
Step 1: Identify base case in recursion
Recursive functions must have a condition to stop calling themselves to avoid infinite loops.Step 2: Check options for base case
void func() { if(condition) func(); else return; } has an if condition that stops recursion; others either lack base case or use loops incorrectly.Final Answer:
void func() { if(condition) func(); else return; } -> Option BQuick Check:
Recursive functions must have base case [OK]
- Missing base case causing infinite recursion
- Confusing loops with recursion calls
- Using infinite loops inside recursive functions
#include <iostream>
int factorial(int n) {
if (n == 0) return 1;
else return n * factorial(n - 1);
}
int main() {
std::cout << factorial(4);
return 0;
}Solution
Step 1: Understand factorial recursion
factorial(4) = 4 * factorial(3), factorial(3) = 3 * factorial(2), and so on until factorial(0) = 1.Step 2: Calculate factorial(4)
factorial(4) = 4 * 3 * 2 * 1 = 24.Final Answer:
24 -> Option DQuick Check:
4! = 24 [OK]
- Confusing factorial with sum
- Forgetting base case returns 1
- Multiplying incorrectly
int sum(int n) {
if (n == 0) return 0;
else return n + sum(n);
}Solution
Step 1: Check recursive call argument
The function calls sum(n) again without decreasing n, causing infinite recursion.Step 2: Correct recursive call
It should call sum(n - 1) to reduce n each time and reach base case.Final Answer:
Recursive call uses sum(n) instead of sum(n - 1) -> Option AQuick Check:
Recursion requires decreasing argument [OK]
- Calling recursion with same argument causing infinite loop
- Confusing sum with product
- Missing base case
Solution
Step 1: Understand tree traversal
Printing all root-to-leaf paths requires exploring multiple branches at each node.Step 2: Compare recursion and loops for branching
Loops handle linear repetition well but struggle with multiple branches; recursion naturally explores each branch by calling itself.Final Answer:
Because loops cannot handle multiple branching paths easily -> Option CQuick Check:
Recursion naturally handles branching [OK]
- Thinking loops can easily replace recursion for trees
- Assuming recursion is always faster
- Believing loops cannot access nodes
Ready to prove it?
Pass the test and this pattern moves unknown
