One corridor to the end

Depth-First Search

The analogy

In a maze you pick a corridor and follow it as far as it goes. Dead end? Back up to the last junction and take the next corridor. DFS commits to a path completely before considering alternatives.

Visualizer

One corridor to the end

step 1 / 15
ABCDEFGH

Start at A. A stack holds where to go next โ€” last in, first out.Stack: A

๐Ÿ“– In depth โ€” the full reference

DFS โ€” everything worth knowing

factvaluenote
time / spaceO(V + E) / O(V)same touch-count as BFS; the ORDER differs, not the cost
data structureSTACK โ€” explicit, or the call stack via recursionrecursion IS DFS borrowing the machine's stack
guaranteereaches everything reachablebut paths found are NOT shortest โ€” that is BFS's job
superpowerscycle detection, topological sort, connected components, maze solving, backtrackingModules 6โ€“7 are built on these
memory vs BFSO(depth) vs O(width)deep narrow graph โ†’ DFS cheap; shallow wide โ†’ BFS queue explodes
recursion depth limitdeep graphs overflow the call stackiterative stack version is immune โ€” know both
three coloursunvisited / in-progress / donean edge to an IN-PROGRESS node = a cycle (the deadlock detector)

Python: recursive and iterative DFS

import sys
# sys.setrecursionlimit(200000)  # default ~1000 frames โ€” deep graphs need more

def dfs(adj, start, seen=None, order=None):
    seen = seen if seen is not None else set()   # never a mutable default!
    order = order if order is not None else []
    seen.add(start)
    order.append(start)
    for nb in adj[start]:
        if nb not in seen:
            dfs(adj, nb, seen, order)
    return order

# Iterative twin โ€” no depth limit (reverse neighbours to match recursive order):
def dfs_iter(adj, start):
    order, seen, stack = [], set(), [start]
    while stack:
        node = stack.pop()
        if node in seen: continue
        seen.add(node)
        order.append(node)
        stack.extend(reversed(adj[node]))
    return order
def dfs(adj, start):
    seen, stack, order = set(), [start], []
    while stack:
        v = stack.pop()          # LIFO
        if v in seen:
            continue
        seen.add(v)
        order.append(v)
        stack.extend(adj[v])
    return order
Check yourself

Which finds the shortest unweighted path?

Practice โ€” write it yourself

dfs_order(adj, start): one corridor to the end โ€” recurse into each unseen neighbour IN LIST ORDER before moving to the next. Return the visit order.

Python 3 ยท runs in your browser ยท your draft is saved locally
๐Ÿ“ My notessaved in this browser