Recursion — Induction in Code
base case ও recursive step-এর নীতি
1. A Function That Calls Itself
Recursion is when a function solves a problem by calling itself on a smaller version of the same problem. It is mathematical induction in executable form.
2. Two Required Ingredients
- Base case — যেখানে recursion থামে।
- Recursive step — ছোট input দিয়ে নিজেকে call করা এবং এর সঠিক ফলাফল ব্যবহার করা।
#include <stdio.h>
long factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive step
}
int main(void) {
int n; scanf("%d", &n);
printf("%d! = %ld\n", n, factorial(n));
return 0;
}
3. The Call Stack — Visualised
প্রতিটি recursive call stack-এ একটি নতুন frame যোগ করে — local variable এবং return address ধরে রাখে। Base case reached হলে frame গুলি একে একে pop হতে শুরু করে।
factorial(3)-এর call stack।
segmentation fault হবে।
4. Classic Recursive Problems
#include <stdio.h>
// Fibonacci — exponential without memoization
long fib(int n) {
if (n < 2) return n;
return fib(n-1) + fib(n-2);
}
// Fast exponentiation — O(log e)
long power(long b, int e) {
if (e == 0) return 1;
long h = power(b, e / 2);
return (e % 2) ? h * h * b : h * h;
}
// Euclidean GCD
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int main(void) {
int n; scanf("%d", &n);
printf("fib(%d) = %ld\n", n, fib(n));
printf("2^%d = %ld\n", n, power(2, n));
printf("gcd(48,36) = %d\n", gcd(48, 36));
return 0;
}
5. Tail Recursion
যদি recursive call-ই ফাংশনের শেষ কাজ হয়, তাহলে compiler সেটিকে সরাসরি loop-এ রূপান্তর করতে পারে — stack বাড়ে না। একে বলা হয় tail call optimization।
#include <stdio.h>
// Tail-recursive factorial helper
long fact_acc(int n, long acc) {
if (n <= 1) return acc;
return fact_acc(n - 1, acc * n); // tail call
}
int main(void) {
printf("10! = %ld\n", fact_acc(10, 1));
return 0;
}
6. When to Use Recursion
✅ Good Fit
- Tree / graph traversal (natural recursion)
- Divide & conquer (merge sort, quicksort)
- Backtracking (N-queens, permutations)
- Problems defined recursively
⚠️ Usually Worse
- Simple sequential loops
- Very deep recursion (stack overflow risk)
- Tight performance code (frame overhead)
- Naive Fibonacci — use memoization/iteration
7. Practice Problems
- Recursive factorial.Recursive factorial।
✨ Show Answer
উপরের Section 2-এর
factorial.c-ই পুরো উত্তর। - Recursive sum from 1 to n.১ থেকে n-এর যোগফল recursively।
✨ Show Answer
sum.c — stdin: 100#include <stdio.h> long sum(int n) { return n <= 0 ? 0 : n + sum(n - 1); } int main(void) { int n; scanf("%d", &n); printf("%ld\n", sum(n)); return 0; } - Fast power in O(log n) recursively.O(log n) সময়ে recursive fast power।
✨ Show Answer
উপরের Section 4-এর
classics.c-এরpowerfunction-ই উত্তর। - Recursive GCD (Euclid).Recursive GCD।
✨ Show Answer
Section 4-এর
gcdfunction-ই একপংক্তিতে উত্তর:return b ? gcd(b, a%b) : a; - Recursive Fibonacci — then memoized — then iterative. Compare for n = 40.Recursive Fibonacci, তারপর memoized, তারপর iterative — n = 40-এ তুলনা করুন।
✨ Show Answer
fib_three.c#include <stdio.h> long fib_slow(int n) { return n < 2 ? n : fib_slow(n-1) + fib_slow(n-2); } long memo[100]; long fib_memo(int n) { if (n < 2) return n; if (memo[n]) return memo[n]; return memo[n] = fib_memo(n-1) + fib_memo(n-2); } long fib_it(int n) { long a = 0, b = 1; for (int i = 0; i < n; i++) { long t = a + b; a = b; b = t; } return a; } int main(void) { int n = 30; // fib_slow on 40 is very slow; using 30 here printf("slow : %ld\n", fib_slow(n)); printf("memo : %ld\n", fib_memo(n)); printf("iter : %ld\n", fib_it(n)); return 0; }Naive O(2ⁿ), memoized O(n), iterative O(n) কিন্তু ধ্রুব মেমরি।
- Reverse a string using recursion (in place).Recursion ব্যবহার করে string in-place reverse করুন।
✨ Show Answer
rev_str.c#include <stdio.h> #include <string.h> void rev(char *s, int i, int j) { if (i >= j) return; char t = s[i]; s[i] = s[j]; s[j] = t; rev(s, i + 1, j - 1); } int main(void) { char s[] = "ABCL TECH"; rev(s, 0, strlen(s) - 1); printf("%s\n", s); return 0; } - Tower of Hanoi — print all moves for n disks.Tower of Hanoi — n টি disk-এর সব move প্রিন্ট করুন।
✨ Show Answer
hanoi.c — stdin: 3#include <stdio.h> void hanoi(int n, char from, char via, char to) { if (n == 0) return; hanoi(n - 1, from, to, via); printf("move disk %d from %c to %c\n", n, from, to); hanoi(n - 1, via, from, to); } int main(void) { int n; scanf("%d", &n); hanoi(n, 'A', 'B', 'C'); return 0; } - Check whether a string is a palindrome using recursion.Recursion দিয়ে palindrome check করুন।
✨ Show Answer
rec_pal.c#include <stdio.h> #include <string.h> int pal(const char *s, int i, int j) { if (i >= j) return 1; if (s[i] != s[j]) return 0; return pal(s, i + 1, j - 1); } int main(void) { const char *s = "madam"; printf("%s is %sa palindrome\n", s, pal(s, 0, strlen(s) - 1) ? "" : "not "); return 0; } - Count digits of a number recursively.Recursively একটি সংখ্যার digit গুনুন।
✨ Show Answer
rec_digits.c — stdin: 987654#include <stdio.h> int digits(long n) { return n == 0 ? 0 : 1 + digits(n / 10); } int main(void) { long n; scanf("%ld", &n); printf("%d\n", n == 0 ? 1 : digits(n)); return 0; } - Print the binary representation of n recursively.Recursively একটি সংখ্যার binary প্রিন্ট করুন।
✨ Show Answer
rec_bin.c — stdin: 42#include <stdio.h> void bin(unsigned int n) { if (n > 1) bin(n / 2); putchar('0' + n % 2); } int main(void) { unsigned int n; scanf("%u", &n); bin(n); putchar('\n'); return 0; } - Recursive binary search on a sorted array.Sorted array-তে recursive binary search।
✨ Show Answer
bs_rec.c#include <stdio.h> int bs(int a[], int lo, int hi, int key) { if (lo > hi) return -1; int m = lo + (hi - lo) / 2; if (a[m] == key) return m; return key < a[m] ? bs(a, lo, m - 1, key) : bs(a, m + 1, hi, key); } int main(void) { int a[] = {1, 3, 7, 12, 19, 25, 42}; printf("index of 19 = %d\n", bs(a, 0, 6, 19)); return 0; } - Generate all permutations of a 4-letter string (backtracking).একটি ৪-অক্ষরের string-এর সমস্ত permutation (backtracking) প্রিন্ট করুন।
✨ Show Answer
perm.c#include <stdio.h> #include <string.h> void perm(char *s, int i, int n) { if (i == n) { puts(s); return; } for (int k = i; k < n; k++) { char t = s[i]; s[i] = s[k]; s[k] = t; perm(s, i + 1, n); t = s[i]; s[i] = s[k]; s[k] = t; } } int main(void) { char s[] = "ABCD"; perm(s, 0, 4); return 0; } - Generate all subsets of
{1,2,3}using backtracking.Backtracking দিয়ে {1,2,3}-এর সমস্ত subset প্রিন্ট করুন।✨ Show Answer
subsets.c#include <stdio.h> int a[] = {1, 2, 3}; int pick[3], n = 3; void gen(int i) { if (i == n) { putchar('{'); for (int k = 0; k < n; k++) if (pick[k]) printf(" %d", a[k]); puts(" }"); return; } pick[i] = 0; gen(i + 1); pick[i] = 1; gen(i + 1); } int main(void) { gen(0); return 0; } - Solve N-Queens for n = 4.n = 4-এর জন্য N-Queens সমাধান করুন।
✨ Show Answer
nqueens.c#include <stdio.h> #include <stdlib.h> #define N 4 int q[N], count = 0; int safe(int r, int c) { for (int i = 0; i < r; i++) if (q[i] == c || abs(q[i] - c) == r - i) return 0; return 1; } void solve(int r) { if (r == N) { count++; return; } for (int c = 0; c < N; c++) if (safe(r, c)) { q[r] = c; solve(r + 1); } } int main(void) { solve(0); printf("%d solutions for %d-queens\n", count, N); return 0; } - Prove by induction that
factorial(n) == n!.Induction দিয়ে প্রমাণ করুনfactorial(n) == n!।✨ Show Answer
Base (n = 0 বা 1):
factorial(1) = 1 = 1!। ✓ Inductive step: ধরে নিনfactorial(k) == k!। তাহলেfactorial(k+1) = (k+1) * factorial(k) = (k+1) * k! = (k+1)!। ✓ ∎ - Convert
fact_accto an iterative version and show they are equivalent.fact_acc-কে iterative version-এ রূপান্তর করুন এবং সমতা দেখান।✨ Show Answer
fact_compare.c#include <stdio.h> long fact_acc(int n, long acc) { if (n <= 1) return acc; return fact_acc(n - 1, acc * n); } long fact_loop(int n) { long acc = 1; while (n > 1) { acc *= n; n--; } return acc; } int main(void) { for (int n = 1; n <= 10; n++) printf("n=%d rec=%ld loop=%ld %s\n", n, fact_acc(n, 1), fact_loop(n), fact_acc(n, 1) == fact_loop(n) ? "✓" : "✗"); return 0; }Tail recursion যেকোনো সময়ই একটি while loop-এ রূপান্তর করা যায়।
Glossary (শব্দকোষ)
| Term | Meaning | বাংলায় |
|---|---|---|
| Recursion | A function calling itself to solve a smaller instance. | একটি ফাংশন নিজেকে call করে ছোট সমস্যা সমাধান। |
| Base Case | The smallest case that returns directly without recursing. | Recursion ছাড়াই সরাসরি ফেরত — সবচেয়ে ছোট ক্ষেত্র। |
| Recursive Case | The case that reduces the problem and calls itself. | সমস্যা ছোট করে নিজেকে call করার ক্ষেত্র। |
| Call Stack | The stack of active function calls. | চালু থাকা function call-গুলোর stack। |
| Stack Frame | One activation record on the call stack. | Call stack-এর একটি entry। |
| Stack Overflow | Recursion too deep — call stack runs out of memory. | অনেক গভীর recursion-এ stack-এর memory শেষ। |
| Tail Recursion | Recursive call is the last action — convertible to a loop. | সর্বশেষ action হিসেবে recursive call। |
| Mutual Recursion | Two functions calling each other. | দুটি function পরস্পরকে call করছে। |
| Tree of Calls | The branching structure recursive calls form. | Recursive call-গুলোর শাখাযুক্ত গঠন। |
| Memoization | Caching recursive results to avoid recomputation. | পুনরাবৃত্ত হিসাব এড়াতে ফলাফল cache করা। |
| Induction | Mathematical proof technique mirroring recursion. | Recursion-এর সমান গণিতীয় প্রমাণের কৌশল। |
| Backtracking | Recursive search that undoes choices on failure. | ব্যর্থতায় সিদ্ধান্ত ফিরিয়ে নিয়ে recursive খোঁজা। |
Summary — Module 12
Base case + recursive step = recursion. Trust the recursive call. Each call is a stack frame. Tail recursion can match loops in performance. Classic problems — factorial, GCD, trees, backtracking — are natural fits.