Wiki
Core13 min read

Graph traversal: BFS and DFS

Breadth-first explores level by level with a queue; depth-first plunges with a stack; both visit every reachable vertex in O(V + E).

Searching a list is easy because there is only one way to move. In a graph you must choose a direction at every node, and the choice determines the order in which you see things. There are two canonical strategies: explore broadly with a queue, or dive deeply with a stack. Everything else is a variation.

The only difference is what you take next

Both algorithms keep a container of discovered-but-unvisited nodes. BFS takes the oldest (a queue); DFS takes the newest (a stack). Swap the container and you swap the exploration order — the code is otherwise the same.

Pick a starting node and step through both orders on the same graph.

Traverse the same graph with a queue and with a stack

ABCDEF
current ●frontier ●visited ●

queue (front left)

B , C

visit order

A

Step 1 of 6.

BFS reaches the nearest nodes first, which is what you want for shortest paths in an unweighted graph. DFS commits to a branch and backtracks, which suits cycle detection and topological order. Both mark a node the moment they first reach it, or they revisit forever in a graph with cycles.

BFS visits every node at distance kk before any node at distance k+1k+1, so it finds the shortest path in unweighted graphs — measured in number of edges. It uses a queue and records each node's distance when first discovered:

from collections import deque
 
def bfs(graph, start):
    seen = {start}
    queue = deque([start])
    order = []
    while queue:
        node = queue.popleft()
        order.append(node)
        for neighbour in graph[node]:
            if neighbour not in seen:
                seen.add(neighbour)
                queue.append(neighbour)
    return order

Mark a node as seen when you enqueue it, not when you dequeue it; otherwise a node can be queued several times before it is first processed.

DFS follows one branch as far as it goes, then backtracks. It is naturally recursive — the call stack is the stack — or written iteratively with an explicit stack. It is the right tool for:

  • detecting cycles,
  • topological sorting a directed acyclic graph,
  • finding connected components,
  • solving mazes and puzzles where any path will do.
def dfs(graph, node, seen=None):
    if seen is None:
        seen = set()
    seen.add(node)
    for neighbour in graph[node]:
        if neighbour not in seen:
            dfs(graph, neighbour, seen)
    return seen

Cost and correctness

Both run in O(V+E)O(V + E) time: every vertex enters the container once, and every edge is examined once for each endpoint. That is linear in the size of the graph, which is optimal — you cannot do better than looking at the input. The only correctness trap is the cycle: without a visited set, traversal loops forever.

Weighted graphs need more than BFS

BFS finds the fewest edges, not the smallest total weight. When edges carry weights, the shortest path is Dijkstra's algorithm (a priority queue instead of a plain queue), and with negative weights you need Bellman-Ford. Using BFS on a weighted graph gives a confidently wrong answer.

Illustrative vs real

The demo graph has six nodes and is small enough to draw. Real graphs have millions and are stored as adjacency lists; recursion depth can exceed Python's limit on long paths, so production DFS is often iterative. The O(V+E)O(V+E) bound and the queue-versus-stack distinction are unchanged.

Check yourself

Eduspheria wiki · Programming & Data Structures, Algorithms

0 / 5 answered

  1. 1Which container does breadth-first search use?
    Multiple choice
  2. 2BFS finds the shortest path in a graph with weighted edges.
    True / false
  3. 3Which traversal is naturally expressed with recursion because the call stack provides the needed structure?
    Short answer
  4. 4A graph has V = 20 vertices and E = 35 edges. In big-O terms with unit coefficients, how many operations does a single traversal perform?
    steps
    Numeric answer
  5. 5What happens if BFS or DFS omits the visited set on a cyclic graph?
    Multiple choice

From the assignment paper

Modeled on NITJ AI-507, Assignment/Quiz

0 / 5 answered

  1. 1A depth-first traversal of a binary tree is written as a three-step recursion. Which order does the classic form visit the nodes in?
    Multiple choice
  2. 2For running BFS and DFS in Python, how is a graph most often stored?
    Multiple choice
  3. 3What is a graph with no cycles called?
    Multiple choice
  4. 4What makes a directed graph strongly connected?
    Multiple choice
  5. 5A connected acyclic graph, in other words a tree, has 12 vertices. How many edges does it have?
    edges
    Numeric answer

Where next: string matching — searching for a pattern inside a text, with the same halving and re-use ideas in a different guise.