C++ Recursion

Understanding functions that call themselves

🔄 What is Recursion?

Recursion is a programming technique where a function calls itself to solve smaller subproblems. It's like breaking a big problem into smaller, similar pieces until you reach a simple base case.


// Simple recursive function to calculate factorial
int factorial(int n) {
    if (n <= 1) return 1;  // Base case
    return n * factorial(n - 1);  // Recursive call
}
                                    

Output for factorial(5):

5! = 5 × 4 × 3 × 2 × 1 = 120

Key Recursion Concepts

🛑

Base Case

The stopping condition that prevents infinite recursion

if (n <= 1) return 1;
🔄

Recursive Call

Function calling itself with modified parameters

return n * factorial(n - 1);
📚

Call Stack

Memory structure storing function calls

factorial(3) → factorial(2) → factorial(1)
âš¡

Tail Recursion

Optimized recursion where recursive call is last

return helper(n-1, acc*n);

🔹 Basic Recursion Example

Recursion involves a function calling itself to solve problems by breaking them into smaller subproblems. A classic example is a countdown: void countdown(int n) { if (n>0) { cout << n; countdown(n-1); } }. Recursion simplifies algorithms for tasks like tree traversal, factorial computation, or divide-and-conquer strategies. However, it requires base cases to avoid infinite loops and mindful stack usage. Recursion is a fundamental technique in C++ for elegant solutions to repetitive or hierarchical problems.

#include <iostream>
using namespace std;

void countdown(int n) {
    if (n <= 0) {  // Base case
        cout << "Blast off!" << endl;
        return;
    }
    cout << n << " ";  // Print current number
    countdown(n - 1);  // Recursive call
}

int main() {
    countdown(5);
    return 0;
}

Output:

5 4 3 2 1 Blast off!

🔹 Fibonacci Sequence

The Fibonacci sequence is a classic example of recursion in programming. Each number in the series is the sum of the two preceding ones, starting from 0 and 1. For instance, the sequence begins 0, 1, 1, 2, 3, 5, 8, 13, and continues infinitely. This pattern appears in nature, mathematics, and computer algorithms, often used to teach recursive problem-solving and dynamic programming techniques to optimize repeated calculations.

#include <iostream>
using namespace std;

int fibonacci(int n) {
    if (n <= 1) return n;  // Base cases: fib(0)=0, fib(1)=1
    return fibonacci(n-1) + fibonacci(n-2);  // Recursive relation
}

int main() {
    for (int i = 0; i < 8; i++) {
        cout << fibonacci(i) << " ";
    }
    return 0;
}

Output:

0 1 1 2 3 5 8 13

🔹 Tree Traversal

Recursion is exceptionally well-suited for navigating tree-like data structures. Methods like in-order, pre-order, and post-order traversal use recursive calls to visit each node systematically. For example, an in-order traversal of a binary search tree visits the left subtree, then the root node, then the right subtree, producing a sorted output. This approach simplifies complex hierarchical data processing.

#include <iostream>
using namespace std;

struct TreeNode {
    int data;
    TreeNode* left;
    TreeNode* right;
    
    TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};

void inorderTraversal(TreeNode* root) {
    if (root == nullptr) return;  // Base case
    
    inorderTraversal(root->left);   // Visit left subtree
    cout << root->data << " ";        // Process current node
    inorderTraversal(root->right);  // Visit right subtree
}

For a binary tree with nodes 1,2,3:

Output: 2 1 3 (left-root-right order)

🧠 Test Your Knowledge

What happens if a recursive function has no base case?