Python · Algorithms · Recursion

Complete Guide to Recursion in Python

Recursion is a technique where a function calls itself to solve a smaller version of the same problem. It is a core concept in algorithms, data structures, and problem solving.

DEFINITION

1. What Is Recursion?

Recursion happens when a function calls itself to solve a smaller part of a problem.

A recursive function must have:

2. Why Is Recursion Useful?

Recursion is especially useful for problems with:

Real-life analogies:

3. Basic Recursion Example: Countdown

This function prints a countdown from n to 1, then prints "Done!". It uses recursion to reduce the problem size with each call.

Output for countdown(5):

5 4 3 2 1 Done!

4. Factorial Using Recursion

Factorial is defined as:

n! = n × (n-1) × (n-2) × ... × 1 1! = 1 0! = 1 (by definition)

Recursive definition

We can define factorial recursively as:

def factorial(n):
    if n == 1:              # Base case
        return 1
    return n * factorial(n - 1)   # Recursive case

How factorial(5) works

Each call reduces n by 1 until it reaches the base case:

factorial(5)
= 5 * factorial(4)

= 5 * 4 * factorial(3)

= 5 * 4 * 3 * factorial(2)

= 5 * 4 * 3 * 2 * factorial(1)

= 5 * 4 * 3 * 2 * 1

= 120

Step-by-step evaluation


= 5 * 4 * 3 * factorial(2)

= 5 * 4 * 3 * 2 * factorial(1)

= 5 * 4 * 3 * 2 * 1

= 120

5. Fibonacci Using Recursion

The Fibonacci sequence is defined as:


F(0) = 0

F(1) = 1

F(n) = F(n-1) + F(n-2) for n ≥ 2
def fib(n):
    if n <= 1:              # Base cases
        return n
    return fib(n - 1) + fib(n - 2)  # Recursive case

Call tree for fib(4)

fib(4)
├── fib(3)

│ ├── fib(2)

│ ├── fib(2)

│ │ ├── fib(1) = 1

│ │ └── fib(0) = 0

│ └── fib(1) = 1

└── fib(2)

├── fib(1) = 1

└── fib(0) = 0

This version is simple but inefficient for large n because it recomputes many values. (You typically optimize it with memoization or iteration.)

6. Recursion vs Iteration

Many recursive algorithms can also be written using loops.

FeatureRecursionIteration
Code readabilityOften more elegantSometimes more verbose
Memory usageHigher (call stack)Lower
PerformanceCan be slower in PythonUsually faster
Best forTrees, graphs, divide & conquerSimple loops, linear scans

7. Tail Recursion & Recursion Limits

Tail recursion is a special case where the recursive call is the last operation in the function. Some languages optimize tail calls to avoid growing the call stack.

7.1 Tail Recursion

A function is tail recursive if the recursive call is the last operation in the function.

def factorial_tail(n, acc=1):
    if n == 1:
        return acc
    return factorial_tail(n - 1, acc * n)

In some languages, tail recursion is optimized to avoid extra stack frames. Python does NOT perform tail recursion optimization, so deep recursion can still overflow.

7.2 Python Recursion Limit

import sys
print(sys.getrecursionlimit())  # often 1000 by default

You can increase this limit, but it is risky:

import sys
sys.setrecursionlimit(5000)  # Use with caution!

Deep recursion can lead to crashes. For very deep problems, consider iterative solutions or using data structures like stacks.

Always ensure your recursive functions have proper base cases to prevent infinite recursion.

Test code here: (It will show that the code is valid but no output will be displayed)

DATA STRUCTURES

8. Recursion in Trees & Graphs

Recursion is a natural fit for traversing hierarchical data structures like trees and graphs.

8.1 In-Order Traversal of a Binary Tree

In-order traversal visits the left subtree, the node, then the right subtree:

def inorder(node):
    if not node:
        return
    inorder(node.left)
    print(node.value)
    inorder(node.right)

8.2 Depth-First Search (DFS) in a Graph

DFS explores as far as possible along each branch before backtracking:

def dfs(graph, node, visited=None):
    if visited is None:
        visited = set()
    if node in visited:
        return
    visited.add(node)
    print(node)

    for neighbor in graph[node]:
        dfs(graph, neighbor, visited)
SORTING

9. Recursion in Sorting Algorithms

Many efficient sorting algorithms use recursion to divide and conquer the problem.

9.1 Merge Sort (Divide & Conquer)

Merge sort divides the array into halves, sorts each half recursively, then merges them:

def merge_sort(arr):
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])

    # merge two sorted halves
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    result.extend(left[i:])
    result.extend(right[j:])
    return result

9.2 Quick Sort

Quick sort selects a pivot, partitions the array, then sorts the partitions recursively:

def quick_sort(arr):
    if len(arr) <= 1:
        return arr

    pivot = arr[0]
    left  = [x for x in arr[1:] if x < pivot]
    right = [x for x in arr[1:] if x >= pivot]

    return quick_sort(left) + [pivot] + quick_sort(right)

10. Common Mistakes in Recursion

Common pitfalls when writing recursive functions include:

11. How to Design a Recursive Solution

For any recursive problem, follow this pattern:

  1. Define the problem in terms of smaller subproblems.
  2. Identify the base case (smallest, simplest input).
  3. Write the recursive case that reduces the input.
  4. Ensure progress toward the base case every call.

General template:

def solve(problem):
    # 1. Base case
    if is_simple(problem):
        return simple_answer(problem)

    # 2. Reduce the problem
    subproblem = make_smaller(problem)

    # 3. Recursive call
    subresult = solve(subproblem)

    # 4. Combine result
    return combine(problem, subresult)

12. Classic Problems Using Recursion

Here are some common recursive exercises to practice your skills:

12.1 Common Recursive Exercises

These problems are very common in interviews and are great practice for mastering recursion.

13. Summary

In this guide, you learned:

Recursion is a powerful tool in your programming toolbox. With practice, it becomes an intuitive way to think about complex, structured problems.