Skip to main content

Recursive Algorithms Explained

Okay, imagine you have a big box. 📦

Inside that box is a smaller box. Inside THAT box is an even smaller box. This keeps going... and going... until you find a tiny box that's too small to open anymore. That tiny box is empty — that's the end!

That's basically what recursion is. It's when you tell a computer: "To solve this problem, do the same exact thing again, but on a smaller piece of it." And it keeps doing that, over and over, until the piece gets so small there's nothing left to do — and then it stops.

Two important rules for this to work:

  1. The "stop" rule (grown-ups call it the base case) — this is the tiny box that won't open anymore. Without this, the computer would keep opening boxes FOREVER and get super confused (this is called a "stack overflow" — like a tower of blocks stacked too high and it falls over!).
  2. The "keep going, but smaller" rule (called the recursive case) — every time, the problem gets a little bit smaller, moving closer to that tiny final box.

A fun example: Say you want to count how many cookies are in a jar, but you can only see one cookie at a time.

  • You pick up 1 cookie and say "that's 1, plus whatever's left in the jar"
  • Then you ask yourself the SAME question again, but for a jar with one less cookie
  • You keep doing this...
  • ...until the jar is empty (the stop rule!) — and you say "0 cookies left"
  • Then all your answers add up going backward: 1+1+1+1+0 = however many cookies!

1. The Big Idea (recap)

Recursion = a function that calls itself to solve a smaller version of the same problem, until the problem is so tiny it can be solved directly (the "stop" box).

Every recursive function needs:

  • Base case = the tiny box that won't open (tells it when to STOP)
  • Recursive case = "do the same thing again, but smaller" (moves closer to the base case)

2. When Should You Actually Use It?

Good times to use recursion:

  • The problem is naturally nested — like folders inside folders, or family trees, or a tree shape
  • Breaking a big math puzzle into smaller pieces (like Fibonacci numbers)
  • You want code that's short and easy to read

Times to think twice:

  • If it's really deep (opens a million boxes), your computer's "memory shelf" (the stack) could get too full and crash — this is called a stack overflow
  • If speed really matters, a loop (iteration) is often faster

3. Where Recursion Shows Up in Real Life (well, real code)

🌳 Trees and Graphs

Trees are literally built like nesting boxes — a tree has a root, and each branch is a smaller tree inside it! So recursion is perfect for walking through them.

Python — visiting every part of a tree (in order):

class TreeNode:
    def __init__(self, value=0, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

def in_order_traversal(node):
    if node:                      # if the box isn't empty
        in_order_traversal(node.left)   # look left
        print(node.value)               # look at this box
        in_order_traversal(node.right)  # look right

JavaScript version:

function inOrderTraversal(node) {
    if (node) {
        inOrderTraversal(node.left);
        console.log(node.value);
        inOrderTraversal(node.right);
    }
}

C++ version:

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

void inOrderTraversal(TreeNode* node) {
    if (node) {
        inOrderTraversal(node->left);
        std::cout << node->value << std::endl;
        inOrderTraversal(node->right);
    }
}

🗺️ Exploring a Maze/Graph (DFS)

Imagine exploring a maze by picking a path, and if it's a dead end, backing up and trying another path. That's Depth-First Search — very recursive!

def dfs(graph, node, visited):
    if node not in visited:
        visited.add(node)
        print(node)
        for neighbor in graph[node]:
            dfs(graph, neighbor, visited)

✂️ Divide and Conquer (splitting the pile in half)

Imagine you have a huge pile of toys to sort. Instead of sorting the whole pile at once, you split it into two smaller piles, sort those, then combine them back together, sorted!

Merge Sort (Python):

def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2
        left_half = arr[:mid]
        right_half = arr[mid:]
        merge_sort(left_half)   # sort the smaller left pile
        merge_sort(right_half)  # sort the smaller right pile
        # ...then combine them back together (merge step)

Quick Sort (Java) — pick one toy as a "pivot," put smaller toys on one side, bigger on the other, then repeat on each side:

public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pivotIndex = partition(arr, low, high);
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }
}

🧠 Dynamic Programming (remembering answers so you don't repeat work)

Imagine you're counting cookies and you already counted a group before — instead of recounting them, you just remember the answer! This trick is called memoization.

def fibonacci(n, memo={}):
    if n in memo:
        return memo[n]       # already know this answer!
    if n <= 1:
        return n
    memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
    return memo[n]

♟️ Backtracking (try it, and undo if it doesn't work)

Like placing chess queens on a board so none of them can attack each other — you try a spot, and if it doesn't work, you take it back and try somewhere else.

bool solveNQueens(int board[], int col, int n) {
    if (col >= n) return true;   // all queens placed!
    for (int i = 0; i < n; i++) {
        if (isSafe(board, i, col, n)) {
            board[col] = i;
            if (solveNQueens(board, col + 1, n)) return true;
        }
    }
    return false;   // didn't work, backtrack
}

➗ Math Stuff

Some math is literally defined recursively:

  • Factorial: n! = n × (n-1)!
  • GCD (greatest common divisor):
function gcd(a, b) {
    if (b === 0) return a;
    return gcd(b, a % b);
}

4. The Good and the Bad

👍 Good stuff:

  • Code can be short and match how you'd explain the problem out loud
  • Great for nested/tree-shaped problems

👎 Bad stuff:

  • Forgetting the base case = infinite boxes = crash (stack overflow)
def factorial(n):
    return n * factorial(n - 1)  # 🚨 no stop rule! Never ends!
  • Can use lots of memory (each call takes a spot on the stack, like a tower of blocks)
  • Sometimes recalculates the same thing over and over (wasteful!) unless you use memoization

5. Making Recursion Faster

Memoization — remember answers you already solved (shown above with the cookie/Fibonacci example)

Tail recursion — do the "multiplying" before calling yourself again, so the computer doesn't need to remember as much:

# Regular way (remembers more)
def factorial(n):
    if n == 0: return 1
    return n * factorial(n - 1)

# Tail-recursive way (remembers less!)
def tail_factorial(n, accumulator=1):
    if n == 0: return accumulator
    return tail_factorial(n - 1, n * accumulator)

6. Recursion vs. Loops (Iteration)

Think of it like two ways to eat a plate of cookies:

  • Recursion = "eat one cookie, then hand the plate to a copy of yourself to do the same thing" (elegant, but uses more "helpers")
  • Iteration (loop) = "just keep eating cookies one at a time yourself, in a line" (usually faster, uses less memory)
# Recursive
def factorial(n):
    if n == 0: return 1
    return n * factorial(n - 1)

# Iterative (loop)
def factorial(n):
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result

Use recursion when: the problem is naturally nested (trees, folders) and readability matters most. Use loops when: performance matters, or the recursion could get really deep.


That's really the whole picture! It all comes back to: break it into a smaller version of the same problem, know when to stop, and watch out for doing the same work twice.

Want me to show you a visual diagram of one of these (like the Fibonacci calls branching out, or the Tower of Hanoi) so you can literally see the nesting boxes in action?

Popular posts from this blog

How to Check if Someone is Connected to Your Machine in Linux

Picture this: you glance at your system monitor and notice your CPU is humming along even though you're not running anything demanding. Or maybe your internet feels sluggish for no obvious reason. A small, uneasy thought creeps in — is someone else on my machine right now? For Linux users, this isn't something you have to wonder about. Linux ships with a powerful set of built-in tools that let you see exactly who's connected, who's logged in, and what your network is doing at any given moment. You don't need to be a security expert to use them — you just need to know where to look. This guide walks you through the practical, no-nonsense steps to check for unauthorized connections on your Linux system, with real commands you can run right now. Why Monitoring Network Connections Matters Every device on a network — including your own Linux machine — communicates using an IP address. When another device or user connects to your system, that connection shows up as a trac...

How to Set Up a Linux Web Server and Host an HTML Page Easily

Setting up a web server on Linux means spending a fair amount of time in the terminal — Linux leans heavily on the command line rather than clicking through menus, so you'll be typing out instructions more often than not.  If you're new to this, it can feel a little intimidating at first, but the good news is you don't need to become a Linux wizard overnight. A handful of core commands will get you surprisingly far. A few you'll lean on constantly: cd — move between directories ls — see what's in the current directory mkdir — create a new folder nano or vim — edit files right there in the terminal sudo — run something with administrator privileges Get comfortable with these and you'll be able to navigate around, tweak configuration files, and install software without much trouble. You don't need to memorize everything — you just need to be confident enough to follow along with clear instructions, which is exactly what this guide aims to give you....

Linux Network Troubleshooting

If you've spent any time as a sysadmin — or honestly, just as someone who's had to fix their own home network at 11pm — you know that connectivity issues are one of the most common headaches out there. The good news is that a handful of core tools and a methodical approach can take you from "why isn't this working" to a root cause pretty quickly.  This guide walks through the essentials: configuring interfaces, managing routes, and diagnosing problems when things go sideways. Configuring Network Interfaces Your network interfaces are the actual bridge between your machine and the outside world, so getting them configured correctly is step one for any kind of reliable connectivity. Doing It Manually ifconfig is the old-school, tried-and-true tool for this on Unix-like systems. To see everything currently configured, run: ifconfig -a If you need to manually set up a specific interface — assigning an IP, a netmask, and bringing it online — it looks like this: ifconf...