Minimum Spanning Trees & Disjoint Set Union
Cut property theorem, Prim's greedy vertex expansion, Kruskal's edge sorting, and Disjoint Set Union (DSU) with path compression and rank.
Reinforce your mental model: run, pause, and inspect live pointers with our interactive visualizer:
Minimum Spanning Trees (MST) interconnect all vertices in a weighted undirected graph with minimum total weight and zero cycles. Founded on the fundamental Cut Property, greedy edge-selection via Kruskal's algorithm with Disjoint Set Union (DSU) and vertex-growth via Prim's algorithm with priority queues achieve near-linear network optimization.
1. Executive Summary & Learning Objectives
#Formulated by Otakar Borůvka in 1926 for electrical grid design, Joseph Kruskal in 1956, and Robert C. Prim in 1957, the Minimum Spanning Tree problem is a cornerstone of combinatorial optimization. An MST spans all vertices with exactly edges while minimizing the total edge weight sum. The efficiency of Kruskal's algorithm is driven by Disjoint Set Union (DSU), whose inverse Ackermann complexity was proven by Robert Tarjan in 1975.
By the end of this chapter, you will be able to:
- Prove the Cut Property and demonstrate why the minimum-weight crossing edge across any graph cut must belong to the MST.
- Implement Disjoint Set Union (DSU / Union-Find) with Path Compression and Union by Rank, achieving amortized operations.
- Execute Kruskal's edge-based greedy algorithm in time, tracing cycle rejections and subset merges.
- Implement Prim's vertex-growth greedy algorithm in time using a Min-Priority Queue.
- Contrast Prim's and Kruskal's performance characteristics across sparse () and dense () network topologies.
2. Minimum Spanning Tree Fundamentals & The Cut Property
#Given a connected, undirected, weighted graph , a Spanning Tree is an acyclic subgraph that connects all vertices using exactly edges.
A Minimum Spanning Tree (MST) is a spanning tree whose sum of edge weights is minimized:
The Cut Property (Foundation of Greedy MST Algorithms)
#- Cut: A partition of vertex set into two non-empty disjoint subsets .
- Crossing Edge: An edge such that and .
Formal Proof by Exchange Argument:
- Assume for contradiction that an MST does not contain the minimum-weight crossing edge with weight .
- Since is a spanning tree, there exists a unique simple path between and in .
- Because and , this path must cross the cut at least once via another crossing edge .
- Construct a new spanning tree by removing and adding .
- The weight of is:
- Since is the strictly minimum-weight crossing edge across cut , , which yields .
- This contradicts the assumption that was a Minimum Spanning Tree. Thus, must belong to the MST.
3. Disjoint Set Union (DSU / Union-Find)
#Disjoint Set Union manages a collection of disjoint dynamic sets over universe supporting two fundamental operations:
find(x): Identifies the unique canonical representative (root) of the set containing .union(x, y): Merges the set containing with the set containing .
The Two Cardinal Optimizations
#| Optimization Strategy | Mechanics | Standalone Complexity | Combined Amortized Bound |
|---|---|---|---|
| Union by Rank / Size | Always attach the root of the tree with smaller depth under the root of the deeper tree. | — | |
| Path Compression | During find(x), update parent pointers of all visited nodes directly to the root. |
Robert Tarjan (1975) proved that combining Union by Rank and Path Compression achieves an amortized bound governed by the Inverse Ackermann Function . For all practical computation, DSU operations run in strictly constant time.
export class DisjointSetUnion {
private parent: Int32Array;
private rank: Uint8Array;
constructor(size: number) {
this.parent = new Int32Array(size);
this.rank = new Uint8Array(size);
for (let i = 0; i < size; i++) {
this.parent[i] = i; // Each element is its own representative initially
this.rank[i] = 0;
}
}
public find(i: number): number {
if (this.parent[i] !== i) {
// Path compression: flatten tree directly to representative root
this.parent[i] = this.find(this.parent[i]);
}
return this.parent[i];
}
public union(x: number, y: number): boolean {
const rootX = this.find(x);
const rootY = this.find(y);
if (rootX === rootY) {
return false; // Elements already in same set; adding edge would form a cycle!
}
// Union by rank
if (this.rank[rootX] < this.rank[rootY]) {
this.parent[rootX] = rootY;
} else if (this.rank[rootX] > this.rank[rootY]) {
this.parent[rootY] = rootX;
} else {
this.parent[rootY] = rootX;
this.rank[rootX]++;
}
return true;
}
}4. Kruskal's Algorithm (Greedy Edge-Selection)
#Joseph Kruskal (1956) formulated an edge-centric greedy algorithm:
- Sort all edges in non-decreasing order of weight: .
- Initialize a DSU with singleton sets.
- For each candidate edge in sorted order:
- If
dsu.find(u) !== dsu.find(v): Adding will not form a cycle. Add to the MST and calldsu.union(u, v). - If
dsu.find(u) === dsu.find(v): Discard (it connects two vertices already in the same tree, which would create a cycle).
- If
- Terminate when edges have been added.
export interface MSTEdge {
u: number;
v: number;
weight: number;
}
export function kruskal(
edges: MSTEdge[],
numVertices: number
): { mstEdges: MSTEdge[]; totalWeight: number } {
// Step 1: Sort edges ascending by weight - O(E log E)
const sortedEdges = [...edges].sort((a, b) => a.weight - b.weight);
const dsu = new DisjointSetUnion(numVertices);
const mstEdges: MSTEdge[] = [];
let totalWeight = 0;
// Step 2: Iterate through sorted edges
for (const edge of sortedEdges) {
if (dsu.union(edge.u, edge.v)) {
mstEdges.push(edge);
totalWeight += edge.weight;
if (mstEdges.length === numVertices - 1) break;
}
}
return { mstEdges, totalWeight };
}5. Step-by-Step Dry Run State Trace: Kruskal's Algorithm
#Consider an undirected graph with 4 vertices and edges:
| Step | Candidate Edge | Weight | find(u) vs find(v) | Cycle Test | DSU Action Taken | MST Edge Set | Total Weight |
|---|---|---|---|---|---|---|---|
| 1 | Disjoint | union(0, 1) root is . | |||||
| 2 | Disjoint | union(0, 2) root is . | |||||
| 3 | Cycle Detected! | Discard edge ! | |||||
| 4 | Disjoint | union(0, 3) root is . | |||||
| Exit | — | — | — | — | edges chosen. Terminate! | Final MST: |
6. Prim's Algorithm (Greedy Vertex-Growth)
#Robert C. Prim (1957) formulated a vertex-centric algorithm that mirrors Dijkstra:
- Start at an arbitrary root vertex .
- Maintain a Min-Priority Queue of crossing edges connecting vertices currently inside the growing MST tree to unvisited vertices outside.
- Greedily extract the crossing edge with minimum weight.
- Add the newly connected vertex to the MST and push its incident edges into the heap.
- Repeat until all vertices are included.
export interface PrimAdjEdge {
to: number;
weight: number;
}
export function prim(
adj: PrimAdjEdge[][],
numVertices: number
): { mstEdges: MSTEdge[]; totalWeight: number } {
const inMST = new Uint8Array(numVertices);
const mstEdges: MSTEdge[] = [];
let totalWeight = 0;
// Min-Priority Queue storing [weight, toVertex, fromVertex]
const pq: [number, number, number][] = [[0, 0, -1]];
while (pq.length > 0 && mstEdges.length < numVertices - 1) {
pq.sort((a, b) => a[0] - b[0]);
const [w, u, parent] = pq.shift()!;
if (inMST[u]) continue;
inMST[u] = 1;
if (parent !== -1) {
mstEdges.push({ u: parent, v: u, weight: w });
totalWeight += w;
}
for (const edge of adj[u]) {
if (!inMST[edge.to]) {
pq.push([edge.weight, edge.to, u]);
}
}
}
return { mstEdges, totalWeight };
}7. Comparative Analysis: Prim vs. Kruskal
#| Architectural Metric | Prim's Algorithm | Kruskal's Algorithm |
|---|---|---|
| Algorithmic Paradigm | Vertex-Growth (grows a single contiguous tree) | Edge-Selection (grows a forest of trees, coalescing components) |
| Core Data Structure | Min-Priority Queue (Binary or Fibonacci Heap) | Disjoint Set Union (DSU) + Edge Array Sorting |
| Time Complexity | ( with Fib Heap) | |
| Auxiliary Space | ||
| Optimal Graph Domain | Dense Graphs () | Sparse Graphs () |
| Disconnected Graphs | Computes Minimum Spanning Tree of single component | Computes Minimum Spanning Forest automatically |
8. Common Traps, Edge Cases & Implementation Pitfalls
#- Disconnected Graphs and Infinite Loops:
- In disconnected graphs, an MST spanning all vertices is physically impossible. Kruskal terminates with fewer than edges (producing a Minimum Spanning Forest). Prim's queue will empty before visiting all vertices. Always check
mstEdges.length === numVertices - 1.
- In disconnected graphs, an MST spanning all vertices is physically impossible. Kruskal terminates with fewer than edges (producing a Minimum Spanning Forest). Prim's queue will empty before visiting all vertices. Always check
- Omitting Path Compression:
- Implementing DSU with Union by Rank alone yields operations. Omitting both rank and path compression degrades DSU to linear linked chains, causing Kruskal to degrade to .
- Graph with Negative Edge Weights:
- Both Kruskal's and Prim's algorithms operate correctly on negative edge weights. Unlike Dijkstra, MST algorithms only require relative edge weight comparisons and do not accumulate path sums along paths.
9. Real-World Applications & Practice Problems
#Production Systems
#- Telecommunications & Power Grid Design: Minimizing physical fiber-optic cable or electrical wire installation costs connecting municipal substations.
- Cluster Analysis (Single-Linkage Hierarchical Clustering): Removing the largest edges from an MST partitions data points into clusters with maximized inter-cluster separation.
- Approximation Algorithms for TSP: The Christofides algorithm uses MST construction as a foundational step to guarantee a -approximation for metric Traveling Salesperson Problems.
Practice Problems
#- Min Cost to Connect All Points (LeetCode 1584) — Complete Euclidean graph MST using Prim's or Kruskal's algorithm.
- Redundant Connection (LeetCode 684) — Detect the cycle-forming edge in an undirected graph via DSU.
- Number of Operations to Make Network Connected (LeetCode 1319) — Connected components counting via DSU.
10. References & Academic Attribution
#- Borůvka, O. (1926). O jistém problému minimálním (On a certain minimal problem). Práce Moravské Přírodovědecké Společnosti, 3(3), 37–58.
- Kruskal, J. B. (1956). On the shortest spanning subtree of a graph and the traveling salesman problem. Proceedings of the American Mathematical Society, 7(1), 48–50.
- Prim, R. C. (1957). Shortest connection networks and some generalizations. Bell System Technical Journal, 36(6), 1389–1401.
- Tarjan, R. E. (1975). Efficiency of a good but not linear set union algorithm. Journal of the ACM (JACM), 22(2), 215–225.
- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2022). Introduction to Algorithms (4th ed.), Chapter 21 (Minimum Spanning Trees) & Chapter 19 (Data Structures for Disjoint Sets). MIT Press.