Recursion — Induction in Code

base case ও recursive step-এর নীতি

~30 min Intermediate 16 practice problems Live code

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.

Recursion মানে একটি ফাংশন একই সমস্যার ছোট একটি version-এ নিজেকেই call করে সমাধান করে। এটি আসলে গাণিতিক induction-এরই executable রূপ।

2. Two Required Ingredients

  • Base case — যেখানে recursion থামে।
  • Recursive step — ছোট input দিয়ে নিজেকে call করা এবং এর সঠিক ফলাফল ব্যবহার করা।
factorial.c — stdin: 6
#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) factorial(2) factorial(1) ← base case returns 1 → 2 × 1 = 2 → 3 × 2 = 6 final result: 6 Figure 12.1 — factorial(3)-এর call stack।
Stack Overflow অত্যধিক গভীর recursion প্রোগ্রামের stack memory শেষ করে দেয় (সাধারণত কয়েক MB)। প্রতিটি level memory ব্যয় করে — গভীরতা খুব বড় হলে segmentation fault হবে।

4. Classic Recursive Problems

classics.c — stdin: 10
#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।

tail.c
#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

  1. Recursive factorial.
    Recursive factorial।
    ✨ Show Answer

    উপরের Section 2-এর factorial.c-ই পুরো উত্তর।

  2. 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; }
  3. Fast power in O(log n) recursively.
    O(log n) সময়ে recursive fast power।
    ✨ Show Answer

    উপরের Section 4-এর classics.c-এর power function-ই উত্তর।

  4. Recursive GCD (Euclid).
    Recursive GCD।
    ✨ Show Answer

    Section 4-এর gcd function-ই একপংক্তিতে উত্তর: return b ? gcd(b, a%b) : a;

  5. 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) কিন্তু ধ্রুব মেমরি।

  6. 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;
    }
  7. 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;
    }
  8. 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;
    }
  9. 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; }
  10. 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; }
  11. 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;
    }
  12. 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; }
  13. 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; }
  14. 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; }
  15. 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)!। ✓ ∎

  16. Convert fact_acc to 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 (শব্দকোষ)

TermMeaningবাংলায়
RecursionA function calling itself to solve a smaller instance.একটি ফাংশন নিজেকে call করে ছোট সমস্যা সমাধান।
Base CaseThe smallest case that returns directly without recursing.Recursion ছাড়াই সরাসরি ফেরত — সবচেয়ে ছোট ক্ষেত্র।
Recursive CaseThe case that reduces the problem and calls itself.সমস্যা ছোট করে নিজেকে call করার ক্ষেত্র।
Call StackThe stack of active function calls.চালু থাকা function call-গুলোর stack।
Stack FrameOne activation record on the call stack.Call stack-এর একটি entry।
Stack OverflowRecursion too deep — call stack runs out of memory.অনেক গভীর recursion-এ stack-এর memory শেষ।
Tail RecursionRecursive call is the last action — convertible to a loop.সর্বশেষ action হিসেবে recursive call।
Mutual RecursionTwo functions calling each other.দুটি function পরস্পরকে call করছে।
Tree of CallsThe branching structure recursive calls form.Recursive call-গুলোর শাখাযুক্ত গঠন।
MemoizationCaching recursive results to avoid recomputation.পুনরাবৃত্ত হিসাব এড়াতে ফলাফল cache করা।
InductionMathematical proof technique mirroring recursion.Recursion-এর সমান গণিতীয় প্রমাণের কৌশল।
BacktrackingRecursive 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.

Next Module → Arrays — পাশাপাশি সাজানো মেমরি।