Section 5 · 9 min read
Graph traversals, MST and shortest paths
BFS and DFS with edge classification, topological sort and strongly connected components, minimum spanning trees, and single-source and all-pairs shortest paths with their limits.
On this page
Representations
| Adjacency list | Adjacency matrix | |
|---|---|---|
| Space | ||
| Test edge | ||
| List neighbours of | ||
| BFS or DFS |
Lists suit sparse graphs; matrices suit dense graphs and edge tests. Unless stated otherwise, GATE assumes adjacency lists.
Breadth-first search
BFS(G, s):
for each v: dist[v] = infinity; parent[v] = nil
dist[s] = 0; Q = queue containing s
while Q not empty:
u = dequeue(Q)
for each v in adj[u]:
if dist[v] == infinity:
dist[v] = dist[u] + 1; parent[v] = u
enqueue(Q, v)
- Visits vertices in non-decreasing distance from . In an unweighted graph
dist[v]is the shortest path length in edges. - The parent pointers form a BFS tree of shortest paths.
- In an undirected graph, every non-tree edge joins vertices whose levels differ by at most 1. So BFS has only tree and cross edges, never back edges in the DFS sense.
- Applications: unweighted shortest paths, bipartiteness (an edge inside one level means an odd cycle), connected components, 0-1 BFS with a deque for weights in {0, 1}.
Depth-first search
DFS(G):
for each u: color[u] = WHITE
time = 0
for each u: if color[u] == WHITE: visit(u)
visit(u):
color[u] = GRAY; time = time + 1; d[u] = time
for each v in adj[u]:
if color[v] == WHITE: parent[v] = u; visit(v)
color[u] = BLACK; time = time + 1; f[u] = time
Parenthesis theorem: for any the intervals and are either disjoint or nested. is a descendant of exactly when .
White-path theorem: becomes a descendant of if and only if, at time , there is a path from to made entirely of white vertices.
Edge classification (directed graphs)
When edge is explored from :
| Colour of | Edge type | Time relation |
|---|---|---|
| White | Tree | discovered now |
| Gray | Back (to an ancestor, includes self-loops) | |
| Black, | Forward (to a non-child descendant) | |
| Black, | Cross |
In an undirected graph every edge is a tree edge or a back edge. A directed graph has a cycle if and only if DFS finds a back edge.
Topological sort
A linear order of a DAG's vertices with every edge pointing forward. Two methods, both :
- DFS: output vertices in decreasing order of finishing time. For every edge in a DAG, .
- Kahn: repeatedly remove a vertex with in-degree 0. If vertices remain and none has in-degree 0, there is a cycle.
A DAG has a unique topological order exactly when it contains a Hamiltonian path.
Strongly connected components
Kosaraju: run DFS on and record finishing times; run DFS on the transpose in decreasing order of those times; each tree of the second DFS is one SCC. Time . The component graph (SCCs contracted) is always a DAG.
Minimum spanning trees
Kruskal (sort edges, add if no cycle, union-find, ) and Prim (grow one tree with a priority queue, with a binary heap, with an array) are covered with proofs in the greedy notes. The facts asked most often:
- Cut property: the lightest edge across any cut is in some MST.
- Cycle property: the unique heaviest edge on a cycle is in no MST.
- Distinct weights mean a unique MST.
- To count MSTs, group edges by weight; inside each group count how many ways the edges can connect the components formed by lighter edges.
Single-source shortest paths
All algorithms use relaxation: if , set and record as the parent.
| Algorithm | Weights | Time |
|---|---|---|
| BFS | unweighted | |
| DAG shortest path (relax in topological order) | any, no cycles | |
| Dijkstra, binary heap | non-negative | |
| Dijkstra, array | non-negative | |
| Dijkstra, Fibonacci heap | non-negative | |
| Bellman-Ford | any, detects negative cycles | |
| Floyd-Warshall (all pairs) | any, no negative cycles |
Dijkstra
Dijkstra(G, s):
d[v] = infinity for all v; d[s] = 0
Q = min-priority queue of all vertices keyed by d
while Q not empty:
u = extract_min(Q) // d[u] is now final
for each edge (u, v, w):
if d[u] + w < d[v]:
d[v] = d[u] + w; decrease_key(Q, v, d[v])
Correctness rests on one claim: when is extracted, no shorter path to can exist, because any other path must leave the finalised set through a vertex with a label at least and then only add non-negative weights.
Dijkstra's limitations
- Negative edges break the claim above. A vertex finalised early can later be reached more cheaply through a negative edge, and its descendants keep the wrong value. Adding a constant to every edge does not fix this, because paths with more edges get penalised more.
- Negative cycles make shortest paths undefined; Dijkstra cannot detect them. Use Bellman-Ford.
- Dijkstra does work on graphs with cycles, and on undirected graphs with non-negative weights.
- With all edge weights equal, Dijkstra behaves like BFS but costs a log factor more.
- A shortest-path tree depends on the source, and it differs from an MST in general.
Worked examples
Worked example 1: BFS levels
Undirected graph with adjacency lists in alphabetical order: A: B, C. B: A, D, E. C: A, F. D: B, G. E: B, G. F: C, G. G: D, E, F. Run BFS from A.
Dequeue A: enqueue B, C (distance 1). Dequeue B: enqueue D, E (distance 2). Dequeue C: enqueue F (distance 2). Dequeue D: enqueue G (distance 3). E, F, G add nothing new. Visit order A, B, C, D, E, F, G. Distances: B, C = 1; D, E, F = 2; G = 3. The edges E-G and F-G are non-tree edges between levels 2 and 3, and none of them skips a level.
Worked example 2: DFS times and edge types
Directed graph: , , , , , , , . The main loop and every adjacency list are in increasing vertex order.
visit(1): . Edge tree, visit(2): . Edge tree, visit(3): . Edge : 1 is gray, back edge. Edge tree, visit(4): , no edges, . Finish 3 (), 2 (). Back at 1, edge : 4 is black and , forward edge. Finish 1 ().
visit(5): . Edge : 4 is black and , cross edge. Edge tree, visit(6): ; edge : 5 is gray, back edge. , .
Summary: tree edges , , , ; back , ; forward ; cross . The back edges reveal the cycles 1-2-3 and 5-6. The SCCs are {1, 2, 3}, {4}, {5, 6}.
Worked example 3: Dijkstra trace
Directed edges: (10), (3), (4), (2), (8), (2), (7), (9). Source A.
| Extracted | ||||
|---|---|---|---|---|
| A (0) | 10 | 3 | ||
| C (3) | 7 | 3 | 11 | 5 |
| E (5) | 7 | 11 | 5 | |
| B (7) | 7 | 9 | ||
| D (9) | 9 |
Final distances: B 7, C 3, D 9, E 5. Extraction order A, C, E, B, D. Note that E is finalised before B even though B was discovered first.
Worked example 4: Where Dijkstra goes wrong
Edges (2), (5), (), (4). Dijkstra extracts s, then a with and sets , then b with . The edge offers , but is already final, and even if its label is lowered, is not relaxed again. Dijkstra reports ; the true distance is . Bellman-Ford gets 5 after at most 3 passes.
Common traps
- BFS gives shortest paths only for unweighted (or equal-weight) graphs.
- In undirected DFS there are no forward or cross edges; in undirected BFS there are no back edges.
- DFS-based topological order is by decreasing finishing time, not discovery time.
- Dijkstra with a negative edge can still give correct answers on some graphs; the claim is that it is not guaranteed.
- Edge order inside adjacency lists changes BFS and DFS trees and times. Questions must fix it; read the convention.
- For a dense graph, array-based Prim or Dijkstra beats the heap version .
- Counting connected components: one per call from the outer DFS or BFS loop.
Quick revision
- BFS and DFS: with lists, with a matrix.
- DFS edge types by colour: white tree, gray back, black forward or cross.
- Cycle in directed graph iff back edge. Topological sort exists iff DAG.
- SCC: Kosaraju with two DFS passes, .
- Dijkstra: non-negative weights only; with a binary heap.
- Bellman-Ford handles negative edges; Floyd-Warshall for all pairs.
- DAG shortest paths in by relaxing in topological order.