๐ง What is Recursion?
Recursion is when a function calls itself to solve a problem.
๐ Simple definition:
โA recursive function is a function that solves a problem by breaking it into smaller sub-problems, and then calls itself to solve those sub-problems.โ
It continues doing this until a certain condition is met (called the base case), which stops the recursion.
๐ฆ Real-Life Analogy
๐ช Russian Dolls (Matryoshka Dolls)
Imagine you have a big doll, and inside it is a smaller one, and then a smaller one inside that, and so on.
Opening each doll leads to the next, until the smallest doll โ thatโs your base case. Then you start closing them in reverse.
๐ ๏ธ How Recursion Works Internally?
<div class="infographic-crecursion">
<style>
.infographic-crecursion {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--line: #ddd6c9;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--ok: #1a7f4e;
--ok-soft: #e3f5ec;
--warn: #b45309;
--warn-soft: #fdf0dc;
--display-font: 'Fraunces', Georgia, serif;
--body-font: 'Inter', -apple-system, sans-serif;
--mono-font: 'IBM Plex Mono', 'Courier New', monospace;
margin: 0 auto;
box-sizing: border-box;
font-family: var(--body-font);
color: var(--ink);
background: var(--paper);
}
.infographic-crecursion[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--line: #2c313d;
--accent: #5b8def;
--accent-soft:#202942;
--ok: #5cd6a0;
--ok-soft: #16342a;
--warn: #e0a458;
--warn-soft: #3a2c14;
}
.infographic-crecursion * { box-sizing: border-box; }
.infographic-crecursion .ig-inner { padding: 1.75rem clamp(1.25rem, 5vw, 3rem) 2rem; }
.infographic-crecursion .ig-title {
font-family: var(--display-font); font-size: clamp(1.4rem, 4.5vw, 1.9rem);
font-weight: 600; text-align: center; margin: 0 0 1.25rem;
}
.infographic-crecursion .code-block {
font-family: var(--mono-font); font-size: 0.82rem; line-height: 1.7;
background: var(--paper-alt); border: 1px solid var(--line); border-radius: 6px;
padding: 0.9rem 1rem; white-space: pre; margin-bottom: 1.5rem;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
max-width: 100%;
}
@media (max-width: 480px) {
.infographic-crecursion .code-block { font-size: 0.72rem; }
}
.infographic-crecursion .code-block .kw { color: var(--accent); }
.infographic-crecursion .code-block .base { color: var(--ok); font-weight: 700; }
.infographic-crecursion .code-block .rec { color: var(--warn); font-weight: 700; }
.infographic-crecursion .code-block .comment { color: var(--ink-soft); }
.infographic-crecursion .controls { display: flex; align-items: center; justify-content: center; gap: 0.6rem; flex-wrap: wrap; padding-top: 1.4rem; }
.infographic-crecursion .n-wrap { position: relative; display: flex; align-items: center; height: 2.4rem; }
.infographic-crecursion .n-tag {
position: absolute; top: -1.3rem; left: 50%; transform: translateX(-50%);
font-size: 0.65rem; font-family: var(--mono-font); color: var(--accent);
background: var(--accent-soft); padding: 0.1rem 0.4rem; border-radius: 4px; white-space: nowrap;
}
.infographic-crecursion .n-input {
width: 4rem; height: 2.4rem; font-family: var(--mono-font); font-size: 1rem; font-weight: 700;
text-align: center; border: 2px solid var(--accent); background: var(--accent-soft); color: var(--accent);
border-radius: 6px; outline: none;
}
.infographic-crecursion .ctrl-btn {
font: inherit; font-size: 0.82rem; font-weight: 600; border: 1px solid var(--line);
background: var(--paper-alt); color: var(--ink); padding: 0.45rem 1rem;
border-radius: 999px; cursor: pointer;
}
.infographic-crecursion .ctrl-btn:hover { border-color: var(--accent); color: var(--accent); }
.infographic-crecursion .ctrl-btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.infographic-crecursion .stack-wrap { margin-top: 1.75rem; min-height: 17rem; }
.infographic-crecursion .frame {
display: flex; align-items: center; gap: 0.6rem;
font-family: var(--mono-font); font-size: 0.8rem;
border: 1px solid var(--line); background: var(--paper-alt);
padding: 0.5rem 0.7rem; border-radius: 6px; margin-bottom: 0.4rem;
opacity: 0; transform: translateY(-8px) scale(0.95);
transition: opacity 0.3s ease, transform 0.3s ease, background 0.3s ease, border-color 0.3s ease;
}
.infographic-crecursion .frame.is-in { opacity: 1; transform: translateY(0) scale(1); }
.infographic-crecursion .frame.is-active { border-color: var(--accent); box-shadow: 0 3px 8px rgba(0,0,0,0.1); }
.infographic-crecursion .frame.is-base { border-color: var(--ok); background: var(--ok-soft); }
.infographic-crecursion .frame.is-returned { border-color: var(--ok); background: var(--ok-soft); opacity: 0.55; }
.infographic-crecursion .frame-call { font-weight: 700; color: var(--ink); white-space: nowrap; }
.infographic-crecursion .frame-status { color: var(--ink-soft); font-size: 0.75rem; }
.infographic-crecursion .frame-status strong { color: var(--ok); }
.infographic-crecursion .result-line {
text-align: center; font-family: var(--mono-font); font-size: 0.95rem; font-weight: 700;
margin-top: 1rem; padding: 0.6rem; border-radius: 6px;
background: var(--ok-soft); color: var(--ok); border: 1px solid var(--ok);
opacity: 0; transform: scale(0.9); transition: opacity 0.3s ease, transform 0.3s ease;
}
.infographic-crecursion .result-line.is-visible { opacity: 1; transform: scale(1); }
.infographic-crecursion .caption {
text-align: center; font-size: 0.85rem; color: var(--ink-soft); margin-top: 1rem; min-height: 1.2em;
}
.infographic-crecursion .caption strong { color: var(--ink); font-family: var(--mono-font); }
@media (prefers-reduced-motion: reduce) {
.infographic-crecursion *, .infographic-crecursion *::before, .infographic-crecursion *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="ig-inner">
<h2 class="ig-title">Recursion in Action</h2>
<div class="code-block"><span class="kw">#include</span> <stdio.h>
<span class="kw">int</span> factorial(<span class="kw">int</span> n) {
<span class="kw">if</span> (n == 0) { <span class="comment">// Base case</span>
<span class="base">return 1;</span>
} <span class="kw">else</span> {
<span class="rec">return n * factorial(n - 1);</span> <span class="comment">// Recursive call</span>
}
}
<span class="kw">int</span> main() {
<span class="kw">int</span> num = 5;
printf(<span class="comment">"Factorial of %d is %d"</span>, num, factorial(num));
<span class="kw">return</span> 0;
}</div>
<div class="controls">
<div class="n-wrap">
<span class="n-tag">num</span>
<input type="number" class="n-input" id="nInput" value="5" min="0" max="7">
</div>
<button class="ctrl-btn primary" id="playBtn">โถ Play</button>
<button class="ctrl-btn" id="restartBtn">โฒ Restart</button>
</div>
<div class="stack-wrap" id="stackWrap"></div>
<div class="result-line" id="resultLine"></div>
<p class="caption" id="caption">Set num, then press Play to watch the call stack grow and unwind.</p>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-crecursion')
|| document.querySelector('.infographic-crecursion');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const nInput = wrapper.querySelector('#nInput');
const playBtn = wrapper.querySelector('#playBtn');
const restartBtn = wrapper.querySelector('#restartBtn');
const stackWrap = wrapper.querySelector('#stackWrap');
const resultLine = wrapper.querySelector('#resultLine');
const caption = wrapper.querySelector('#caption');
let frameEls = [];
let timer = null;
let steps = [];
let idx = -1;
function buildSteps(n) {
steps = [];
// Push phase: factorial(n), factorial(n-1), ... down to factorial(0) (base case)
for (let i = n; i >= 0; i--) {
const isBase = i === 0;
steps.push({
type: 'push', depth: n - i, n: i, isBase,
status: isBase ? 'n == 0 โ base case, return 1' : `n = ${i}, calls factorial(${i - 1})`
});
}
// Unwind phase
let value = 1;
for (let i = 0; i <= n; i++) {
const depth = n - i;
if (i === 0) {
steps.push({ type: 'unwind', depth, n: i, text: 'returns 1', value: 1 });
} else {
const newValue = i * value;
steps.push({ type: 'unwind', depth, n: i, text: `${i} * ${value} = ${newValue}`, value: newValue });
value = newValue;
}
}
steps.push({ type: 'done', n, value });
}
function reset() {
stackWrap.innerHTML = '';
frameEls = [];
resultLine.classList.remove('is-visible');
resultLine.textContent = '';
}
function applyStep(step) {
if (step.type === 'push') {
const frame = document.createElement('div');
frame.className = 'frame is-active' + (step.isBase ? ' is-base' : '');
frame.style.marginLeft = `${step.depth * 1.1}rem`;
frame.innerHTML = `<span class="frame-call">factorial(${step.n})</span><span class="frame-status">${step.status}</span>`;
stackWrap.appendChild(frame);
frameEls[step.depth] = frame;
requestAnimationFrame(() => frame.classList.add('is-in'));
frameEls.forEach(f => f && f.classList.remove('is-active'));
frame.classList.add('is-active');
caption.innerHTML = step.isBase
? `<strong>n = 0</strong> hits the base case โ time to unwind`
: `<strong>n = ${step.n}</strong> calls <strong>factorial(${step.n - 1})</strong>`;
}
if (step.type === 'unwind') {
const frame = frameEls[step.depth];
frame.classList.remove('is-active');
frame.classList.add('is-returned');
frame.querySelector('.frame-status').innerHTML = `<strong>${step.text}</strong>`;
caption.innerHTML = `<strong>factorial(${step.n})</strong> returns <strong>${step.value}</strong>`;
}
if (step.type === 'done') {
resultLine.textContent = `factorial(${step.n}) = ${step.value}`;
resultLine.classList.add('is-visible');
caption.innerHTML = `Done โ unwound all the way back to <strong>factorial(${step.n})</strong>`;
}
}
function stop() {
clearInterval(timer);
timer = null;
playBtn.textContent = 'โถ Play';
}
function advance() {
idx++;
if (idx >= steps.length) { stop(); return; }
applyStep(steps[idx]);
if (idx >= steps.length - 1) stop();
}
function play() {
if (timer) { stop(); return; }
if (idx >= steps.length - 1 || idx === -1) {
restart(false);
}
playBtn.textContent = 'โธ Pause';
timer = setInterval(advance, 700);
advance();
}
function restart(clearCaption = true) {
stop();
idx = -1;
reset();
const n = Math.max(0, Math.min(7, Number(nInput.value) || 0));
nInput.value = n;
buildSteps(n);
if (clearCaption) caption.textContent = 'Set num, then press Play to watch the call stack grow and unwind.';
}
playBtn.addEventListener('click', play);
restartBtn.addEventListener('click', () => restart(true));
nInput.addEventListener('change', () => restart(true));
restart(true);
})();
</script>When a function calls itself:
The current function call pauses.
A new function call is pushed onto the stack.
This continues until the base case is reached.
Then the calls are popped off the stack one by one, finishing each paused call.
๐งฑ This behavior uses something called the Call Stack.
๐งช Components of a Recursive Function
Every recursive function has two main parts:
Base Case (Stopping Condition)
โค The condition where the recursion stops.
โค Prevents infinite recursion.
Recursive Case
โค The part where the function calls itself to solve a smaller problem.
๐ Syntax of a Recursive Function:
return_type function_name(parameters) {
if (base_case_condition) {
return some_value;
} else {
return function_name(smaller_problem); // Recursive call
}
}๐ก Letโs Understand with an Example: Factorial
๐งฎ Factorial of a number n is:
n! = n ร (n - 1) ร (n - 2) ร ... ร 1So,
5! = 5 ร 4 ร 3 ร 2 ร 1 = 120โ Factorial using Recursion:
#include <stdio.h>
int factorial(int n) {
if (n == 0) { // Base case
return 1;
} else {
return n * factorial(n - 1); // Recursive call
}
}
int main() {
int num = 5;
printf("Factorial of %d is %d", num, factorial(num));
return 0;
}Factorial of 5 is 120๐ฏ More Examples of Recursion
The Fibonacci series:
0, 1, 1, 2, 3, 5, 8, ...Where:
fib(n) = fib(n-1) + fib(n-2)
fib(0) = 0, fib(1) = 1int fib(int n) {
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}int power(int x, int n) {
if (n == 0)
return 1;
else
return x * power(x, n - 1);
}int sum(int n) {
if (n == 0)
return 0;
else
return n + sum(n - 1);
}โ ๏ธ Common Mistakes in Recursion
Mistake | What Happens |
|---|---|
โ No base case | Infinite recursion โ stack overflow error |
โ Base case never reached | Stack overflow |
โ Modifying parameters incorrectly | Wrong results |
๐ Recursion vs Loop
Feature | Recursion | Loop |
|---|---|---|
Uses Call Stack | Yes | No |
Code Length | Shorter (often) | Longer (often) |
Performance | Slower (more memory) | Faster |
Complexity | Higher (harder to trace) | Easier to debug |
๐ง Pro Tip: Recursion is elegant, but in practice, loops are more efficient for most real-world C programs.
๐ When to Use Recursion
โ Use recursion when:
The problem is naturally recursive (like trees, graphs).
You can clearly define a base case and recursive case.
Simplicity is more important than performance.
โ Avoid recursion when:
Performance and memory are critical.
The depth of recursion could be too large (causing stack overflow).