Call stack behavior in C++ - Time & Space Complexity
When a program runs functions, it uses a call stack to keep track of where it is. Understanding how this stack grows helps us see how time grows with input.
We want to know how the number of function calls affects the total work done.
Analyze the time complexity of the following recursive function.
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
This function calculates the factorial of a number by calling itself with smaller values until it reaches 1.
Look at what repeats as the function calls itself:
- Primary operation: The recursive call to
factorial(n - 1). - How many times: It repeats once for each number from
ndown to 1, sontimes.
As n grows, the number of calls grows the same way.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 calls |
| 100 | About 100 calls |
| 1000 | About 1000 calls |
Pattern observation: The work grows directly with n. Double n, double the calls.
Time Complexity: O(n)
This means the time to finish grows in a straight line with the input size.
[X] Wrong: "Recursive calls happen all at once, so time is constant."
[OK] Correct: Each call waits for the next one to finish, so calls add up one after another, making time grow with n.
Understanding how the call stack grows helps you explain recursion clearly and shows you can think about how programs use memory and time together.
What if the function called itself twice each time (like in Fibonacci)? How would the time complexity change?
Practice
Solution
Step 1: Understand function call behavior
When a function is called, the program needs to remember where to return after the function finishes.Step 2: Role of the call stack
The call stack adds a new frame on top to store this information and local variables.Final Answer:
It adds a new frame for the function call on top of the stack. -> Option AQuick Check:
Function call = add frame [OK]
- Thinking the stack removes frames on function call
- Believing the stack clears all calls at once
- Confusing call stack with program pause
Solution
Step 1: Identify valid function call from main
void foo() {} int main() { foo(); return 0; } calls foo() from main, which adds a frame to the call stack.Step 2: Check other options for correctness
void foo() { main(); } int main() { return 0; } calls main() from foo(), which is invalid as main should not be called explicitly. int main() { return 0; } void foo() { foo(); } has foo calling itself but foo is not called from main, so no stack change from main. int main() { int x = 5; } has no function calls.Final Answer:
void foo() {} int main() { foo(); return 0; } -> Option CQuick Check:
Valid call from main = void foo() {} int main() { foo(); return 0; } [OK]
- Thinking main can be called like a normal function
- Ignoring function call order
- Confusing declaration with call
#include <iostream>
void print(int n) {
if (n == 0) return;
print(n - 1);
std::cout << n << " ";
}
int main() {
print(3);
return 0;
}Solution
Step 1: Trace recursive calls
print(3) calls print(2), which calls print(1), which calls print(0). At print(0), it returns immediately.Step 2: Print after returning from recursion
After print(0) returns, print(1) prints '1 ', then print(2) prints '2 ', then print(3) prints '3 '.Final Answer:
1 2 3 -> Option BQuick Check:
Recursion prints after calls = 1 2 3 [OK]
- Printing before recursive call instead of after
- Including 0 in output incorrectly
- Confusing order of prints in recursion
void recurse(int n) {
if (n > 0) {
recurse(n + 1);
}
}
int main() {
recurse(1);
return 0;
}Solution
Step 1: Analyze recursion condition
The function calls recurse(n + 1) if n > 0, so n increases each call without stopping.Step 2: Understand call stack effect
Because n never reaches 0 or less, recursion never stops, causing stack frames to pile up until overflow.Final Answer:
Stack overflow due to infinite recursion increasing n. -> Option AQuick Check:
Infinite recursion = stack overflow [OK]
- Assuming recursion stops without base case
- Confusing syntax error with runtime error
- Ignoring infinite growth of parameter
result?int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
int main() {
int result = factorial(4);
return 0;
}Solution
Step 1: Understand factorial recursion
factorial(4) calls factorial(3), factorial(3) calls factorial(2), factorial(2) calls factorial(1), which returns 1.Step 2: Calculate return values step-by-step
factorial(2) = 2 * 1 = 2; factorial(3) = 3 * 2 = 6; factorial(4) = 4 * 6 = 24.Final Answer:
24 -> Option DQuick Check:
4! = 24 [OK]
- Stopping recursion too early
- Adding instead of multiplying
- Confusing base case return value
Ready to prove it?
Pass the test and this pattern moves unknown
