Foundations

What is Recursion?

Recursion is when a function solves a problem by calling itself on a smaller version of that problem. Each call must move toward a base case — a condition simple enough to answer directly without recursing further. Once the base case is reached, the paused calls resolve in reverse order.

Time Depends on the recurrence: time equals the number of recursive calls times the work per call. Factorial is O(n); a full tree traversal is O(n) for n nodes.Space O(d), where d is the maximum recursion depth held on the call stack — O(n) for factorial, and O(h) for a tree of height h.Topic Foundations

The idea: a problem that contains itself

Recursion is the programming version of a simple observation: some problems are built out of smaller copies of themselves. To sort a stack of papers, sort each half and merge them. To count the files inside a folder, count the files in each subfolder and add them up. A recursive function mirrors that structure — it handles one small step directly, then hands the rest of the work to another copy of itself running on a smaller input.

Every recursive function answers two questions. First: what is the smallest case I can solve immediately, without recursing? That is the base case. Second: how do I reduce a bigger case to a smaller one of the same kind, then combine the result? That is the recursive case. Get both right and the function is correct; forget the base case and it calls itself forever.

The mechanics: the call stack

When a function calls itself, the program does not discard the caller — it pauses it. The computer maintains a call stack: a stack of frames, one per active call, each holding that call's local variables and the exact line to return to. factorial(4) calls factorial(3), which calls factorial(2), and so on, so four frames pile up before any of them finishes.

The base case is what lets the stack unwind. factorial(1) returns 1 without recursing, so its frame pops; now factorial(2) can compute 2 × 1 and pop, and control flows back down until factorial(4) returns 24. This is why recursion costs memory: the maximum stack depth is extra space you pay even when the code looks compact. Exceed the limit — Python defaults to roughly 1000 frames — and you get a stack overflow.

Recursion on trees

Recursion shines on data that is itself recursive. A binary tree is either empty, or a node with a left subtree and a right subtree — and each subtree is just a smaller tree. That definition is a base case (empty) plus a recursive case (a node and two subtrees), so traversal code reads almost like the definition itself: handle the empty case, recurse left, visit the node, recurse right.

This is also where recursion beats loops for clarity. Traversing a tree with a loop means managing an explicit stack by hand, while the recursive version lets the call stack do that bookkeeping for you. Watching the calls expand down one branch and collapse back up — then repeat on the next branch — is the moment recursion usually clicks, which is why it helps to see it animate step by step rather than read it cold.

pythonFactorial and in-order tree traversal — each defines a base case, then recurses on a smaller input.
def factorial(n):
    """Return n! using recursion. Assumes n >= 0."""
    # Base case: 0! and 1! are both 1 — stop recursing.
    if n <= 1:
        return 1
    # Recursive case: n! = n * (n - 1)!
    return n * factorial(n - 1)


def inorder(node, visit):
    """Visit a binary tree's values in sorted (in-order) order."""
    if node is None:            # Base case: empty subtree.
        return
    inorder(node.left, visit)   # Recurse left,
    visit(node.value)           # process this node,
    inorder(node.right, visit)  # then recurse right.
Time complexityDepends on the recurrence: time equals the number of recursive calls times the work per call. Factorial is O(n); a full tree traversal is O(n) for n nodes.
Space complexityO(d), where d is the maximum recursion depth held on the call stack — O(n) for factorial, and O(h) for a tree of height h.

Depth is best/average O(log n) for a balanced tree but worst-case O(n) for a degenerate one. Naive recursion that re-solves overlapping subproblems (e.g. plain Fibonacci) can explode to O(2^n) unless memoized.

When to use it

  • Traversing or building tree and graph structures, where each node has the same shape as the whole (DFS, tree height, folder walks).
  • Divide-and-conquer algorithms that split a problem into smaller identical subproblems — merge sort, quicksort, binary search.
  • Problems defined by a recurrence or by exploring choices with undo — factorial, permutations and subsets, and backtracking puzzles like N-Queens.
  • When the recursive version is dramatically clearer than the iterative one, such as flattening arbitrarily nested data.

Watch out for

  • Missing or unreachable base case, or a recursive call that doesn't shrink the input — this causes infinite recursion and a stack overflow.
  • Re-solving the same subproblem repeatedly; naive Fibonacci is O(2^n). Add memoization or convert to dynamic programming when subproblems overlap.
  • Ignoring stack-depth limits: deep linear recursion crashes on large inputs. Rewrite it iteratively (or with an explicit stack) when depth can grow unbounded.
In the interview

Recursion is foundational interview material — expect it both as a direct topic and as the hidden engine behind harder problems. Interviewers use small prompts like factorial, reversing a linked list, or Fibonacci to check that you can name a clean base case and a correctly shrinking recursive case without off-by-one errors. It then reappears everywhere: tree and graph traversal (DFS), divide-and-conquer sorts, and every backtracking question (permutations, subsets, N-Queens) is recursion with undo. What they are really watching is whether you can state the recurrence, reason about its time and space including stack depth, and spot when naive recursion repeats work and should be memoized. Being able to trace the call stack out loud, and to convert a recursive solution to an iterative one on request, signals genuine understanding rather than a memorized template.

Recursion: frequently asked questions

Is recursion hard to learn?

It feels hard at first because you have to trust the function to solve the smaller case before you've finished writing it. Once you internalize the two-part pattern — a base case plus a recursive case that shrinks the input — most recursive functions follow the same shape. Tracing a few small examples by hand, or watching the call stack build and unwind, makes it click much faster than staring at the code.

When should I use recursion instead of a loop?

Reach for recursion when the data or problem is naturally recursive — trees, graphs, nested structures, or divide-and-conquer — where a loop would force you to manage a stack by hand. Prefer a loop for simple linear iteration, or when the recursion depth could grow large enough to overflow the stack. They are equally powerful; it comes down to which one makes the code clearer and safe.

What is the time complexity of a recursive function?

There is no single answer — it equals the number of recursive calls made times the work done per call. Linear recursion like factorial is O(n); balanced divide-and-conquer is often O(n) or O(n log n); and naive recursion that re-solves the same subproblems, like plain Fibonacci, can blow up to O(2^n). You work it out by drawing the recursion tree or solving a recurrence, for example with the Master Theorem.

What causes a stack overflow in recursion?

Every active recursive call stays on the call stack until it returns, so recursion that goes too deep — or never reaches its base case — exhausts the stack and crashes. A missing or unreachable base case causes infinite recursion, but even correct recursion can overflow on very deep inputs. Fixes include making sure the base case is always reached, converting to iteration, or raising the stack limit.

See Recursion as an animated story

Reading the definition is one thing — watching recursion run line by line, then explaining it to an AI interviewer, is how it actually sticks. That is what CodeStory does.