Minimum Spanning Tree: Kruskal's Algorithm
Greedily build a minimum spanning tree by scanning edges in increasing weight order and adding each edge whose endpoints lie in different components — using a disjoint-set structure to detect cycles in near-constant time.
What is a Minimum Spanning Tree?
Given a connected, undirected, weighted graph G = (V, E), a spanning tree is a subgraph that:
- Includes every vertex of
G, - Is connected, and
- Contains no cycles (so it has exactly
V - 1edges).
A minimum spanning tree (MST) is a spanning tree whose total edge weight is minimum among all spanning trees of G.
Classic motivating example: "design the cheapest road network that connects all the towns." Other applications include clustering (single-linkage), network design (electricity, fiber, water), approximate TSP, and image segmentation.
A graph may have multiple MSTs if some edges share weights, but every MST has the same total weight.
The greedy idea — cheapest edge that doesn't form a cycle
Kruskal's strategy is the textbook greedy:
- Sort all edges by weight, smallest first.
- Initialize an empty MST
Tand place every vertex in its own set. - Scan edges in order. For each edge
(u, v, w):- If
uandvare in different components, add the edge toTand merge the components. - If they are in the same component, skip the edge — adding it would create a cycle.
- If
- Stop after adding
V - 1edges.
Why it works (cut property, informal): at any moment, the cheapest edge that crosses between two components must belong to some MST — if a candidate MST didn't contain it, we could swap it in and lower (or match) the total weight.
The magic is how cheaply we test "different components?" — the disjoint-set data structure answers in near-O(1) amortized time.
Step-by-step visualization
Run Kruskal on this 6-vertex weighted graph (vertices A..F renamed 1..6). Step forward and backward with the ← / → arrow keys or the buttons below.
What to watch:
- Node colors show DSU components — every vertex starts as its own color, and accepting an edge merges two colors into one. The small
→rlabel under each vertex is its current DSU root. - The sorted edge list is scanned left to right: the dashed amber edge is under consideration, green edges joined the MST, red struck-through edges were rejected because both endpoints already share a root — adding them would close a cycle.
- The running MST cost accumulates only the accepted weights.
After 5 accepted edges (= V − 1) the tree is complete with total cost 33 — every later edge can only be rejected.
Node color = its component (DSU root, shown under each node). Accepting an edge merges two colors.
Tip: step through with the ← / → arrow keys.
Why Kruskal is correct
Cut property (informal): Let S ⊂ V be any non-empty proper subset, and let e be the cheapest edge crossing between S and V \ S. Then some MST contains e.
At the moment Kruskal considers edge e = (u, v) and finds u, v in different components, consider the cut that separates u's component from the rest. Every edge crossing that cut has weight at least w(e) — otherwise we would have already added a cheaper one and merged the components. So e is a cheapest crossing edge for some cut, and by the cut property e belongs to some MST. Adding it keeps our partial selection a subset of an MST.
Cycle property (informal): the heaviest edge on any cycle is unnecessary. Kruskal naturally enforces this: when scanning by increasing weight, an edge closing a cycle is the heaviest on that cycle (every earlier edge of the cycle has already been processed), and so it can be safely skipped.
Together, these two properties say Kruskal never adds a bad edge and never misses a needed one.
Pseudocode
Kruskal is two lines of idea — sort, then scan with DSU cycle checks — and the code reflects that. The unite call doubles as the cycle test: it returns false exactly when both endpoints already share a root. The C++ tab is a complete program on the visualization's graph; it prints the MST edges and total weight 33.
1KRUSKAL(V, E):2 sort E in non-decreasing order of weight34 for each v in V: MAKE-SET(v)56 T = empty set // edges of the MST7 totalWeight = 08 for each edge (u, v, w) in sorted E:9 if FIND(u) != FIND(v):10 UNION(u, v)11 add (u, v, w) to T12 totalWeight += w13 if |T| == |V| - 1: break1415 return T, totalWeight
Complexity analysis
Three components contribute to the running time:
- Sorting all
Eedges:O(E log E). SinceE ≤ V², this is the same asO(E log V). Ecalls to DSU Find + Union:O(E · α(V)), essentiallyO(E).- Bookkeeping (constructing the result):
O(V).
Total time: O(E log E) = O(E log V), dominated by the sort.
Space: O(V + E) — for the edge list and the DSU.
Kruskal is edge-centric and works very well for sparse graphs (graphs that can be stored conveniently as an edge list). For very dense graphs, Prim's algorithm with a binary heap or Fibonacci heap can be faster in practice.
Complexity Analysis
Time Complexity
O(E log E), which is the same as O(E log V). Sorting dominates; the disjoint-set work is effectively O(E·α(V)).
Space Complexity
O(V + E) — the edge list plus the parent/rank arrays of the DSU.
Kruskal is edge-centric and excels on sparse graphs handed in as an edge list. Prim's algorithm with a binary heap matches it asymptotically and can be faster on dense graphs with an adjacency matrix.