🔁 What is Recursion?
Recursion is when a function calls itself to solve a smaller subproblem.
🧠 Tail Recursion vs Non-Tail Recursion
Feature | Tail Recursion | Non-Tail Recursion |
---|---|---|
Definition | The last action is the recursive call | The recursive call is not the last action |
Optimization | Can be optimized by the compiler (tail call optimization) | Cannot be optimized |
Call stack usage | Uses less stack (can be optimized away) | Uses more stack (each call waits) |
Return after call? | ❌ No further work after recursion | ✅ More work is done after the recursive call |
✅ Tail Recursion Explanation
“The last action is the recursive call”
✅ What It Means (Tail Recursion):
In tail recursion, the very last thing the function does is call itself again — and then immediately return that result.
There’s no additional work to do after the recursive call.
🔁 Example (Tail Recursion):
void tailRecursion(int n)
{
if (n == 0)
return;
cout << n << " ";
tailRecursion(n - 1); // 🔹 This is the LAST action
}
In this function:
tailRecursion(n - 1);
is the last line- After calling itself, nothing else happens.
- So it’s tail recursion ✅
📦 Why It Matters:
Because there’s no work left after the recursive call, the compiler can optimize it by:
- Reusing the current function’s memory.
- Not keeping extra stack frames.
This is called Tail Call Optimization (TCO).
❌ Contrast with Non-Tail Recursion:
int factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1); // 🔹 More work (multiplication) after recursive call
}
Here:
- The recursive call
factorial(n - 1)
runs, - Then we still have to multiply by
n
.
So this is not tail recursion — it’s non-tail recursion.
💡 Summary:
“The last action is the recursive call” means there’s nothing else to do after the function calls itself — no calculations, no operations, no waiting — just call and return.
🔄 Line 2. “Can be optimized by the compiler (tail call optimization)”
✅ What it means:
- When a function is tail recursive (i.e., the recursive call is the last thing it does), the compiler can optimize it by reusing the current function’s memory space, instead of adding a new one on the call stack.
🧠 Why it’s useful:
- Saves memory
- Prevents stack overflow in deep recursion
📦 Example:
void tailRec(int n)
{
if (n == 0)
return;
tailRec(n - 1); // last thing = tail call ✅
}
👉 The compiler may optimize this to use just one stack frame.
⚠️ Note: C++ compilers don’t always guarantee tail call optimization unless you enable specific settings.
🧠 What does “optimize” mean here?
💬 In simple terms:
Optimize means make better or more efficient — especially in terms of speed or memory usage.
🎯 In the context of tail recursion:
Without optimization:
Every recursive call stores its own memory (called a stack frame) like stacking boxes:
tailRec(5)
tailRec(4)
tailRec(3)
tailRec(2)
tailRec(1)
Each call waits for the next one to finish. That uses more memory.
With optimization (Tail Call Optimization):
If the last thing your function does is call itself, the compiler realizes:
“Hey! I don’t need the current function anymore, so I’ll reuse its space.”
So instead of stacking:
[tailRec(5)]
[tailRec(4)]
[tailRec(3)]
...
It replaces the current one:
tailRec(5) → overwritten by tailRec(4) → overwritten by tailRec(3)
✅ Result: Only one box (stack frame) is used the whole time.
🧠 What is Tail Call Optimization?
Tail Call Optimization is a technique used by some compilers (like C++ compilers) to make recursive functions more memory efficient.
✅ When does it happen?
It happens only when a function calls itself as the very last thing it does — this is called a tail call.
📌 Example — Tail Call:
void tailRec(int n)
{
if (n == 0)
return;
tailRec(n - 1); // LAST thing the function does ✅
}
Because there is nothing left to do after the recursive call, the compiler can say:
“Why keep the old function in memory? I’ll just reuse its space for the next one.”
This saves memory by not adding new stack frames.
❌ Not a Tail Call:
factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1); // Multiply happens after recursion ❌
}
Here, the compiler can’t optimize — because it needs to wait for the result of factorial(n - 1)
to do the multiplication.
🧱 How TCO Works (Visually)
Normally (without TCO):
factor(3)
→ factor(2)
→ factor(1)
→ base case
Uses 3 stack frames (one per call).
With TCO, only 1 frame is reused again and again.
Summary
Concept | Meaning |
---|---|
Tail call | A function call that is the last thing done in the function |
Tail Call Optimization | Compiler reuses the same memory (stack frame) to save space |
Benefit | Less memory, avoids stack overflow, faster execution |
Limitation | Only works if nothing happens after the recursive call |
🧪 Fun fact: C++ compilers can perform TCO, but they don’t always do it by default. Some other languages like Scheme or Haskell do it aggressively.
🧠 Line 3. “Uses less stack (can be optimized away)”
✅ What it means:
- Normally, each recursive call uses a new stack frame (memory).
- But in tail recursion, because nothing else needs to be done after the recursive call, the compiler doesn’t need to keep the old stack frame.
➡️ So, it can “optimize it away”, meaning:
“Don’t save the old frame; just overwrite it with the new one.”
This keeps memory use very low, even for large inputs.
📌 So “optimized away” means:
- The compiler removes the extra stack usage
- Saves memory
- Prevents stack overflow for deep recursion
❌ Line 4. “No further work after recursion”
✅ What it means:
In tail recursion, after the recursive call:
- The function doesn’t do anything else.
- It just ends.
🔍 Example:
✅ Tail Recursive:
void printTail(int n)
{
if (n == 0)
return;
cout << n << " ";
printTail(n - 1); // LAST thing → tail recursion
}
- After
printTail(n - 1);
, the function does nothing else → ✅
❌ Non-Tail Recursive:
int factorial(int n)
{
if (n == 0)
return 1;
return n * factorial(n - 1); // Work happens after recursion ❌
}
- After the recursive call
factorial(n - 1)
, we still multiply byn
→ more work is done → ❌ not tail recursive
✅ Tail Recursion Example in C++
#include <iostream>
using namespace std;
void tailRecursion(int n){
if (n == 0)
return;
cout << n << " ";
tailRecursion(n - 1); // recursive call is the LAST statement
}
int main(){
tailRecursion(5); // Output: 5 4 3 2 1
return 0;
}

✅ Tail Recursive because there’s nothing left to do after the recursive call.




Only one box (stack frame) is used the whole time.
🧩 return;
inside tailRecursion(int n)
(n == 0) return;
✅ What it means:
- This
return;
tells the function to stop and exit immediately whenn == 0
. - It’s the base case in recursion — the condition that stops further recursive calls.
🧠 Think of it like:
“If
n
is 0, there’s nothing more to print. Just exit the function.”
🧩 return 0;
inside main()
return 0;
✅ What it means:
main()
is the starting point of your C++ program.- Returning
0
frommain()
means: “The program ended successfully.”
This value (0
) is sent back to the operating system. By convention:
return 0;
= successreturn non-zero;
= error
🔁 Final Summary:
Line | Meaning |
---|---|
return; in tailRecursion | Exit the function (no value needed) |
return 0; in main() | Exit the program successfully (with value 0) |