Recursion Concept and Call Stack Visualization in DSA Rust - Time & Space Complexity
We want to understand how the time taken by a recursive function grows as the input size increases.
Specifically, how many times the function calls itself and what that means for performance.
Analyze the time complexity of the following code snippet.
fn factorial(n: u32) -> u32 {
if n == 0 {
1
} else {
n * factorial(n - 1)
}
}
This code calculates the factorial of a number using recursion by calling itself with a smaller number until it reaches zero.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive call to
factorialwithn - 1 - How many times: Exactly
n + 1times until reaching the base casen == 0
Each increase in input n adds one more recursive call, so the total calls grow linearly.
| Input Size (n) | Approx. Operations (Recursive Calls) |
|---|---|
| 10 | 11 calls |
| 100 | 101 calls |
| 1000 | 1001 calls |
Pattern observation: The number of calls grows directly with n, so doubling n doubles the work.
Time Complexity: O(n)
This means the time taken grows in a straight line with the input size; bigger inputs take proportionally more time.
[X] Wrong: "Recursion always means exponential time because it calls itself many times."
[OK] Correct: This example shows recursion can be simple and linear if each call makes only one smaller call, not multiple calls.
Understanding how recursion grows helps you explain your code clearly and shows you can reason about performance, a key skill in interviews.
"What if the recursive function called itself twice each time? How would the time complexity change?"
Practice
Solution
Step 1: Understand recursion base case role
The base case stops recursion by providing a condition to end calls.Step 2: Analyze missing base case effect
Without a base case, the function keeps calling itself endlessly, filling the call stack.Final Answer:
It causes infinite recursion leading to a stack overflow error. -> Option DQuick Check:
Missing base case = infinite recursion [OK]
- Thinking recursion stops automatically
- Assuming function returns without base case
- Confusing recursion with loops
n?Solution
Step 1: Check function return type and base case
fn factorial(n: u32) -> u32 { if n == 0 { 1 } else { n * factorial(n - 1) } } correctly returns u32 and has base case for n == 0 returning 1.Step 2: Verify recursive call correctness
fn factorial(n: u32) -> u32 { if n == 0 { 1 } else { n * factorial(n - 1) } } calls factorial(n - 1) correctly; others miss return type or have wrong logic.Final Answer:
fn factorial(n: u32) -> u32 { if n == 0 { 1 } else { n * factorial(n - 1) } } -> Option BQuick Check:
Correct syntax = fn factorial(n: u32) -> u32 { if n == 0 { 1 } else { n * factorial(n - 1) } } [OK]
- Omitting return type in function signature
- Using while loop inside recursive function
- Calling factorial with n + 1 causing infinite recursion
fn print_numbers(n: u32) {
if n == 0 {
return;
}
print_numbers(n - 1);
println!("{}", n);
}
fn main() {
print_numbers(3);
}Solution
Step 1: Trace recursive calls
print_numbers(3) calls print_numbers(2), then print_numbers(1), then print_numbers(0) which returns immediately.Step 2: Understand print order after recursion
After reaching base case, prints happen in reverse call order: prints 1, then 2, then 3.Final Answer:
1 2 3 -> Option AQuick Check:
Recursion prints after calls = 1 2 3 [OK]
- Assuming prints happen before recursive call
- Confusing order of execution in recursion
- Ignoring base case effect
fn sum(n: u32) -> u32 {
if n == 1 {
1
} else {
n + sum(n + 1)
}
}Solution
Step 1: Analyze recursive call parameter
The function calls sum(n + 1), which increases n, moving away from base case.Step 2: Understand effect on recursion
Since n grows, base case n == 1 is never reached, causing infinite recursion and stack overflow.Final Answer:
The recursive call uses n + 1 instead of n - 1, causing infinite recursion. -> Option CQuick Check:
Recursive call must reduce n to reach base case [OK]
- Using n + 1 instead of n - 1 in recursion
- Confusing base case condition
- Missing return keyword in else block
reverse("rust")?fn reverse(s: &str) -> String {
if s.is_empty() {
String::new()
} else {
let (first, rest) = s.split_at(1);
format!("{}{}", reverse(rest), first)
}
}
fn main() {
println!("{}", reverse("rust"));
}Solution
Step 1: Understand recursion and string splitting
The function splits the string into first character and rest, then recursively reverses rest and appends first.Step 2: Trace calls for "rust"
reverse("rust") calls reverse("ust") + "r", reverse("ust") calls reverse("st") + "u", and so on, building reversed string "tsur".Final Answer:
"tsur" -> Option AQuick Check:
Recursive reverse builds string backwards = "tsur" [OK]
- Confusing order of concatenation
- Not handling empty string base case
- Assuming original string is returned
Ready to prove it?
Pass the test and this pattern moves unknown
