Iteration repeats a block of instructions using loops (for, while) until a terminating condition is reached.
ALGORITHM SumIterative(n)
sum ← 0
for i ← 1 to n do
sum ← sum + i
end for
return sum
Recursion occurs when a function calls itself with a smaller or simpler version of the problem. Every recursive algorithm must have:
ALGORITHM SumRecursive(n)
if n = 0 then
return 0 // base case
else
return n + SumRecursive(n - 1) // recursive case
end if
SumRecursive(4)
= 4 + SumRecursive(3)
= 4 + 3 + SumRecursive(2)
= 4 + 3 + 2 + SumRecursive(1)
= 4 + 3 + 2 + 1 + SumRecursive(0)
= 4 + 3 + 2 + 1 + 0
= 10
KEY TAKEAWAY: Every recursive call is added to the call stack. The base case stops further calls, then results propagate back up the stack.
ALGORITHM Fibonacci(n)
if n <= 1 then
return n
else
return Fibonacci(n-1) + Fibonacci(n-2)
end if
Note: This naive implementation has exponential time complexity $O(2^n)$ — dynamic programming is vastly more efficient.
| Aspect | Iteration | Recursion |
|---|---|---|
| Control structure | for/while loops |
Self-calls |
| Memory | $O(1)$ extra (typically) | $O(d)$ call stack ($d$ = recursion depth) |
| Readability | More explicit (state visible) | More elegant for naturally recursive problems |
| Performance | Usually faster (no call stack overhead) | Slower if not tail-recursive |
| Problems suited for | Sequential, straightforward problems | Divide-and-conquer, trees, backtracking |
| Stack overflow risk | None | Yes — if recursion depth is very large |
Prefer iteration when:
- The problem has a straightforward loop structure
- Memory efficiency is critical
- Depth of recursion could be very large
Prefer recursion when:
- The problem is naturally self-similar (e.g. tree traversal, binary search, mergesort)
- Recursion leads to cleaner, more readable code
- The problem uses a divide-and-conquer approach
Every recursive algorithm can be converted to an iterative one by using an explicit stack:
# Recursive DFS
def dfs_recursive(graph, start, visited=None):
if visited is None: visited = set()
visited.add(start)
for neighbour in graph[start]:
if neighbour not in visited:
dfs_recursive(graph, neighbour, visited)
return visited
# Iterative DFS (using explicit stack)
def dfs_iterative(graph, start):
visited = set()
stack = [start]
while stack:
v = stack.pop()
if v not in visited:
visited.add(v)
for neighbour in graph[v]:
stack.append(neighbour)
return visited
EXAM TIP: DFS is naturally recursive; BFS is naturally iterative (using a queue). Both can be converted, but their natural form is easier to reason about and less error-prone.