Kodnos
/
Software Engineering

Recursion Explained Like You Are Five (Almost)

Recursion confuses everyone at first. Here is a thorough guide with real examples, step-by-step traces, common pitfalls, and the mental shift you need to write recursive functions confidently.

A
admin
Apr 14, 2026 12 min read 16 views
Recursion Explained Like You Are Five (Almost)

Recursion is one of those concepts that clicks suddenly after confusing you for weeks. I have seen it happen dozens of times with students and junior developers. One day it makes no sense, and the next day everything falls into place.

Let me try to make that click happen right now.

The Simplest Way to Think About It

Imagine you are standing in a line of people, and someone asks you "how many people are in this line?" You cannot see the whole line because it stretches around a corner. So you tap the person behind you on the shoulder and ask: "How many people are behind you, including yourself?"

That person does the same thing — taps the next person and asks the same question. This keeps going until the very last person in line, who looks behind them, sees nobody, and says "just me — one person."

Then each answer flows back up the line. The person in front of them says "two" (themselves plus one). The next says "three." This ripples all the way back to you, and you add yourself to get the final answer.

That is recursion. You solve a big problem by asking someone to solve a slightly smaller version of the same problem. Each person in line is doing the exact same task — they just have fewer people to count.

The Two Rules You Cannot Break

Every recursive function needs exactly two things, and if you miss either one, your code will break in spectacular ways.

Rule 1: The Base Case

The base case is where the recursion stops. It is the answer you know without needing to ask anyone else. In our line example, it is the last person who says "just me — one."

Without a base case, your function calls itself forever. Well, not actually forever — it crashes with a stack overflow error once it runs out of memory. I have done this more times than I would like to admit.

Rule 2: The Recursive Case

The recursive case is where the function calls itself with a smaller or simpler input. Each call must make progress toward the base case. If you are not making the problem smaller with each call, you have an infinite loop disguised as recursion.

Let Us Start Simple: Factorial

The factorial of 5 (written as 5!) is 5 x 4 x 3 x 2 x 1 = 120. Notice how you can express this as: 5! = 5 x 4!, and 4! = 4 x 3!, and so on until 1! = 1.

That recursive pattern gives us:

Python
def factorial(n):
    if n <= 1:        # Base case: we know 1! = 1
        return 1
    return n  factorial(n - 1)  # Recursive case: n! = n  (n-1)!

Let us trace through factorial(4) step by step, because tracing is the single best way to understand recursion:

factorial(4)
  = 4 * factorial(3)
  = 4  (3  factorial(2))
  = 4  (3  (2 * factorial(1)))
  = 4  (3  (2 * 1))          # Base case hit!
  = 4  (3  2)
  = 4 * 6
  = 24

See how the function keeps calling itself, building up a chain of deferred multiplications? When it finally hits the base case, all those multiplications execute in reverse order. This "going down and then coming back up" pattern is the heartbeat of recursion.

A More Interesting Example: Power Function

Calculating x raised to the power n:

Python
def power(x, n):
    if n == 0:            # Base case: anything to the power 0 is 1
        return 1
    if n < 0:             # Handle negative exponents
        return 1 / power(x, -n)
    return x  power(x, n - 1)  # x^n = x  x^(n-1)

This works, but it is O(n) — for power(2, 1000) it makes 1000 recursive calls. We can do better with a clever observation: x^10 = (x^5)^2. This cuts the work in half at each step:

Python
def fast_power(x, n):
    if n == 0:
        return 1
    if n < 0:
        return 1 / fast_power(x, -n)
    if n % 2 == 0:
        half = fast_power(x, n // 2)
        return half * half       # Square the half-power
    return x * fast_power(x, n - 1)

Now it is O(log n). For fast_power(2, 1000), that is about 10 calls instead of 1000. Same result, dramatically less work.

A Practical Example: Searching in a Directory Tree

Recursion is not just academic. Here is something you might actually use in real projects — searching for a file in nested directories:

Python
import os

def find_file(directory, target): for item in os.listdir(directory): path = os.path.join(directory, item) if item == target: return path if os.path.isdir(path): result = find_file(path, target) # Recurse into subdirectory if result: return result return None

# Usage path = find_file("/home/user/projects", "config.yaml")

This is a case where recursion feels completely natural because the data itself is recursive — directories contain directories, which contain more directories. You could write this with a loop and a stack, but the recursive version reads like a description of the algorithm.

Thinking Recursively: The Key Insight

The hardest part of recursion is not the syntax — it is learning to think recursively. Here is the mental shift you need to make:

Stop trying to trace the entire execution in your head.

Instead, trust the recursion. When you write a recursive function, assume the recursive call works correctly and focus on just one level:

1. What is my base case? What is the simplest version of this problem? 2. If I had the answer to a slightly smaller problem, how would I use it to solve the current problem? 3. Does my recursive call actually make the problem smaller?

For factorial: if someone gives me factorial(n-1), I just multiply it by n. I do not need to think about how factorial(n-1) works — I just trust that it does.

This "leap of faith" is the secret to writing recursive functions confidently.

Classic Recursive Problems

Fibonacci Numbers

Each number is the sum of the two before it: 0, 1, 1, 2, 3, 5, 8, 13, 21...

Python
def fib(n):
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)

This is elegant but terribly slow — O(2^n). For fib(40), it makes over a billion calls because it recalculates the same values repeatedly. fib(5) calls fib(3) twice, fib(2) three times, and so on.

Fibonacci with Memoization

The fix is simple — remember values you have already calculated:

Python
def fib(n, memo={}):
    if n in memo:
        return memo[n]
    if n <= 1:
        return n
    memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
    return memo[n]

Now it is O(n). Same logic, same recursive structure, but each value is calculated exactly once. This technique — memoization — is one of the most powerful tools in a programmer's arsenal. It turns exponential algorithms into linear ones.

Binary Search

You probably know binary search as a loop, but it is naturally recursive:

Python
def binary_search(arr, target, low=0, high=None):
    if high is None:
        high = len(arr) - 1
    if low > high:
        return -1  # Not found
    
    mid = (low + high) // 2
    if arr[mid] == target:
        return mid
    elif arr[mid] < target:
        return binary_search(arr, target, mid + 1, high)
    else:
        return binary_search(arr, target, low, mid - 1)

Each call halves the search space — O(log n).

When NOT to Use Recursion

Here is something textbooks rarely emphasize: recursion is not always the best choice. Sometimes a plain loop is clearer, faster, and safer.

Use recursion when:

  • The data structure is naturally recursive (trees, graphs, nested objects, file systems)
  • The problem divides cleanly into smaller subproblems (divide and conquer)
  • Code clarity matters and the recursion depth is manageable
  • You are implementing algorithms that are inherently recursive (quicksort, mergesort, tree traversals)
  • Avoid recursion when:

  • A simple loop would do the same thing more clearly (summing numbers, iterating a list)
  • The recursion could go very deep (Python's default limit is 1000 calls, Java's stack is also finite)
  • Performance is critical and the overhead of function calls matters
  • The recursive solution is harder to understand than the iterative one
  • The Stack Overflow Problem

    Every recursive call adds a frame to the call stack — a chunk of memory that stores the function's local variables and return address. If your recursion goes too deep, you literally run out of stack space:

    Python
    def count_down(n):
        if n == 0:
            return
        count_down(n - 1)

    count_down(10000) # RecursionError: maximum recursion depth exceeded

    Solutions:

  • Convert to iteration when depth is a concern
  • Use tail recursion (some languages optimize this, though Python does not)
  • Increase the recursion limit cautiously: sys.setrecursionlimit(50000)
  • Use an explicit stack data structure to simulate recursion

Recursion in Tree Structures

Trees are where recursion truly shines because a tree is itself a recursive data structure — every subtree is also a tree.

Python
class TreeNode:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def tree_sum(node): if node is None: # Base case: empty tree return 0 return node.val + tree_sum(node.left) + tree_sum(node.right)

def tree_height(node): if node is None: return 0 return 1 + max(tree_height(node.left), tree_height(node.right))

Try writing tree_height without recursion. It is doable, but the code is significantly more complex. This is recursion at its best — expressing a complex traversal in just three lines.

The Takeaway

Recursion is a thinking tool as much as a coding technique. It teaches you to break big problems into smaller ones, to identify base cases, and to trust that solving the small problems correctly will solve the big one.

Start with simple examples — factorial, power, Fibonacci. Trace through them by hand on paper. Once those feel natural, move to trees and graphs. And if you ever feel stuck, remember: the key is not to trace every call in your head. Trust the recursion, focus on one level, and make sure your base case is correct.

Once it clicks, you will start seeing recursive patterns everywhere. And that is when programming gets really fun.

12 MinShare this article
Oğuzhan Berke Özdil
Author

Oğuzhan Berke Özdil

I have been connected to computers since childhood. On this website, I share what I learn and experience while trying to build a strong foundation in software. I completed my BSc in Computer Science at AGH University of Krakow and I am currently pursuing an MSc in Computer Science with a focus on AI & Data Analysis at the same university.