Graph BFS

Breadth-First Search explores a graph layer by layer, finding shortest paths in unweighted graphs.

O(V + E)GraphsShortest Paths
Phase 1f(x)

The Mathematics

Graph definitions, BFS properties, and shortest path theorem

Graph Definition

A graph G=(V,E)G = (V, E) consists of a set of vertices VV and edges EV×VE \subseteq V \times V. We represent it using an adjacency list:

Adj(v)={uV:(v,u)E}\text{Adj}(v) = \{u \in V : (v, u) \in E\}

For an undirected graph, if (u,v)E(u,v) \in E then (v,u)E(v,u) \in E.

BFS Layer Structure

BFS explores vertices in order of their distance from the source ss. Define layers:

Ld={vV:dist(s,v)=d}L_d = \{v \in V : \text{dist}(s, v) = d\}

L0={s}L_0 = \{s\} — the source itself

L1=Adj(s)L0L_1 = \text{Adj}(s) \setminus L_0 — direct neighbors

Ld+1={u:(v,u)E,vLd}idLiL_{d+1} = \{u : (v,u) \in E, v \in L_d\} \setminus \bigcup_{i \leq d} L_i— new vertices reachable from layer dd

FIFO Queue Property

BFS uses a First-In-First-Out queue. This ensures that all vertices at distance dd are processed before any vertex at distance d+1d+1:

Queue order:  L0,L1,L2,\text{Queue order:}\; L_0, L_1, L_2, \ldots

Shortest Path Theorem

Theorem

For an unweighted graph G=(V,E)G = (V,E) and source ss, BFS computes dist(s,v)\text{dist}(s,v) for all vVv \in V reachable from ss, where dist(s,v)\text{dist}(s,v) is the minimum number of edges on any path from ss to vv.

Complexity: Each vertex is enqueued and dequeued at most once, and each edge is examined at most twice (once from each endpoint):

T(V,E)=O(V+E)T(V, E) = O(|V| + |E|)
Phase 2

See It Work

BFS traversal from node A — watch the queue and distance layers

Ad=0BCDEFG

Queue (FIFO)

front
A
back
Layer 0 (d=0)
Layer 1 (d=1)
Layer 2 (d=2)
Layer 3 (d=3)
L0={s},  dist(s,s)=0L_0 = \{s\},\; \text{dist}(s,s) = 0
Step 1 of 8

Initialize: enqueue source node A. Mark A as visited with distance 0.

Phase 3</>

The Code

Mapping graph theory to Python with collections.deque

Mathematical Formulation

visited={s}\text{visited} = \{s\}

Initialize visited set with the source node

Q=deque([s])Q = \text{deque}([s])

FIFO queue ensures layer-by-layer traversal

dist(s)=0\text{dist}(s) = 0

Source has distance 0 from itself

v=Q.popleft()v = Q.\text{popleft}()

Dequeue the front node (FIFO order)

uAdj(v)\forall u \in \text{Adj}(v)

Iterate over all neighbors in adjacency list

dist(u)=dist(v)+1\text{dist}(u) = \text{dist}(v) + 1

Distance grows by 1 each layer — shortest path in unweighted graph

Python Implementation

from collections import deque

def bfs(graph, source):
    visited = {source}              # Track visited nodes
    queue = deque([source])         # FIFO queue
    dist = {source: 0}             # Distance from source
    while queue:                    # Process until empty
        v = queue.popleft()         # Dequeue front
        for u in graph[v]:          # Visit neighbors
            if u not in visited:    # Skip if seen
                visited.add(u)      # Mark visited
                dist[u] = dist[v] + 1  # Set distance
                queue.append(u)     # Enqueue neighbor
    return dist