Prim's Algorithm
Prim’s algorithm builds an MST by growing a single tree from an arbitrary root, repeatedly adding the lightest edge connecting the tree to a vertex outside. It is structurally similar to Dijkstra’s algorithm but uses direct edge weights rather than cumulative path distances.
Algorithm
PRIM(G, w, r):
for each v in G.V:
v.key = INFINITY
v.parent = NIL
r.key = 0
Q = priority queue containing all vertices, keyed by v.key
while Q is not empty:
u = EXTRACT-MIN(Q)
for each v in G.adj[u]:
if v in Q and w(u, v) < v.key:
v.parent = u
v.key = w(u, v)
DECREASE-KEY(Q, v, v.key)
At termination, the edge set forms the MST.
Key Insight
The key of a vertex is the minimum weight of any edge connecting it to the current tree. This differs from Dijkstra, where key is the cumulative distance from the source. In Prim, the key is just the single edge weight, not a path sum.
Correctness
The algorithm maintains the invariant: at the start of each loop iteration, for every vertex not yet extracted, its key is the minimum-weight edge connecting it to the tree (vertices already extracted). When EXTRACT-MIN selects , the edge is the lightest edge crossing the cut (current tree, rest of graph), so it is a safe edge. The correctness follows from the safe-edge theorem.
Formally, at each step the set of extracted vertices forms a tree, and the cut is respected by the tree edges. The extracted vertex is connected via the lightest edge crossing this cut.
Running Time
Using a binary heap:
- Initialisation: , or for BUILD-HEAP
- EXTRACT-MIN operations:
- Up to DECREASE-KEY operations, each :
- Queue membership test via bit array: per check
Total: for connected graphs.
Using a Fibonacci heap:
- EXTRACT-MIN: amortised
- DECREASE-KEY: amortised
Total: , which is better for dense graphs where . The term dominates.
Worked Example
Same graph as the Kruskal example: vertices , root .
Edges: , , , , , , , , .
Initialise: key() = 0, all others . Queue: all vertices.
- Extract (key 0). Update neighbours: key() = 4, key() = 1. Parents: , .
- Extract (key 1). Update neighbours: key() min(4, 3) = 3 (parent ), key() = 5 (parent ), key() = 6 (parent ).
- Extract (key 3). Update neighbours: key() min(5, 2) = 2 (parent ).
- Extract (key 2). Update neighbours: key() min(6, 7) = 6 (no change), key() = 4 (parent ).
- Extract (key 4). Update neighbours: key() min(6, 3) = 3 (parent ).
- Extract (key 3). No unextracted neighbours.
- Queue empty.
MST edges: , , , , . Total weight: (same total as Kruskal via different tree shape).
Prim vs. Dijkstra
| Aspect | Prim | Dijkstra |
|---|---|---|
| Key meaning | Weight of connecting edge | Cumulative distance from source |
| Initialisation | root.key = 0 | s.d = 0 |
| Relax condition | w(u, v) < v.key | u.d + w(u, v) < v.d |
| Update | v.key = w(u, v) | v.d = u.d + w(u, v) |
| Handles | Connected undirected graphs | Directed graphs, non-negative weights |
| Output | MST (tree of minimum total weight) | Shortest path tree |
Summary
| Aspect | Binary heap | Fibonacci heap |
|---|---|---|
| EXTRACT-MIN | amortised | |
| DECREASE-KEY | amortised | |
| Total | ||
| Best for | Sparse graphs | Dense graphs () |
Past Tripos: y2024p2q7, y2023p1q9.