Articles

Recursion vs. Iteration, Explained

Recursion solves a problem by calling itself on smaller inputs; iteration solves it with a loop. Same results, different trade-offs in memory and clarity.

The Lycoris Team The Lycoris Team · · 4 min read
Mathematical equations written on a chalkboard

Recursion solves a problem by having a function call itself on a smaller version of that same problem, until it reaches a base case simple enough to answer directly. Iteration solves the same class of problem with a loop that repeats a set of steps, tracking progress in variables that update each pass. Both can compute the same result — the difference is in how the computer keeps track of “where it is” while doing so.

A side-by-side example: factorial

Iteration keeps state explicitly, in a variable that’s updated on each loop pass:

def factorial_iterative(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result

Recursion keeps state implicitly, on the call stack, by breaking the problem into a smaller version of itself:

def factorial_recursive(n):
    if n <= 1:
        return 1
    return n * factorial_recursive(n - 1)

factorial_recursive(5) calls factorial_recursive(4), which calls factorial_recursive(3), and so on down to the base case n <= 1, at which point each call returns back up the chain, multiplying as it goes. Nothing is stored in a loop variable — the pending multiplication at each level is implicitly held by the call stack until the recursive calls beneath it resolve.

Why the call stack matters

Every recursive call adds a new frame to the call stack — memory that tracks that call’s local variables and where to resume once the call it made returns. A loop, by contrast, doesn’t grow the stack per iteration; it just updates variables in a single stack frame. This is the central practical trade-off: recursion that goes too deep can exhaust the stack and crash with a stack overflow, while an equivalent loop generally won’t, because it isn’t creating new stack frames as it repeats.

This is exactly the same call-stack mechanism that turns up when reasoning about time and space complexity with Big O notation — a recursive function’s space complexity has to account for the depth of the call stack, not just the data it’s processing, which is easy to overlook if you’re only counting the size of the input.

Some languages optimize a specific pattern called tail recursion — where the recursive call is the very last operation in the function, with nothing left to do after it returns — by reusing the current stack frame instead of adding a new one. Not every language guarantees this optimization, though, so relying on it for arbitrarily deep recursion is language-dependent in a way that a loop simply isn’t.

Where recursion is the more natural fit

Some structures and problems are inherently recursive, and forcing them into a loop trades clarity for no real benefit. Traversing a tree — a binary search tree, for instance — is naturally recursive: visit a node, then recurse into its left and right subtrees, each of which is structurally the same problem at a smaller scale. Graph traversal via depth-first search has the same shape. Dynamic programming problems are often first expressed recursively — breaking a problem into overlapping subproblems — before being optimized with memoization or converted into an iterative, bottom-up table-filling approach for better performance.

Divide-and-conquer algorithms are the clearest case: quicksort and mergesort both recursively split a problem into smaller pieces, solve each piece, and combine the results — a shape that maps far more directly onto recursive calls than onto a single loop.

Recursion vs. iteration

RecursionIteration
State trackingImplicit, via the call stackExplicit, via loop variables
Risk of stack overflowYes, for deep enough recursionNo — no growing call stack
Natural fit forTrees, graphs, divide-and-conquerLinear repetition, simple counting
Memory overhead per stepA new stack frameTypically none beyond existing variables
Readability for recursive structuresOften clearer, mirrors the problem’s shapeCan require an explicit stack to simulate recursion

Converting between the two

Any recursive algorithm can be rewritten iteratively — sometimes trivially, sometimes only by maintaining an explicit stack data structure that mimics what the call stack was doing implicitly. See stacks and queues for the data structure that shows up whenever you convert recursion to iteration by hand. This is a common technique when a recursive solution is clean to write but risks overflowing on large or adversarial inputs, and an iterative version with an explicit stack gives you the same logic with predictable, bounded memory use — you trade some of the recursive version’s clarity for control over exactly how state is tracked.

The reverse conversion — turning a loop into recursion — is usually done for clarity or to express a divide-and-conquer structure explicitly, less often for performance, since the iterative version rarely has a memory disadvantage worth trading away.

The takeaway

Recursion and iteration are two ways of tracking progress through a repeated computation: one uses the call stack implicitly, the other uses loop variables explicitly. Recursion tends to read more naturally for problems that are themselves recursively structured — trees, graphs, divide-and-conquer — while iteration avoids the stack-depth risk and often runs with less memory overhead for straightforward repetition. Neither is universally better; the right choice follows the shape of the problem, not a general preference for one style over the other.

The Lycoris Team The Lycoris Team · · 4 min read

The Producer-Consumer Problem, Explained

The producer-consumer problem is a classic concurrency pattern: coordinating producers and consumers around a shared, bounded buffer safely.

#Computer Science #Concurrency #Programming
The Lycoris Team The Lycoris Team · · 4 min read

How Regular Expressions Work Under the Hood

Regular expressions are matched by finite automata or backtracking engines. How regex engines parse patterns, and why some patterns run slowly.

#Computer Science #Algorithms #Developer Tools
The Lycoris Team The Lycoris Team · · 4 min read

P vs NP: What Does 'NP-Complete' Actually Mean?

P is problems solvable quickly; NP is problems whose solutions are quickly checkable. Whether P equals NP is one of computing's open questions.

#Computer Science #Algorithms