GeeksforGeeks Medium

MST — Kruskal's Algorithm

Build a minimum spanning tree by taking edges cheapest-first, skipping any that would close a cycle.

graphmstgreedyunion-find
Open on GeeksforGeeks ↗
02

Intuition

Sort every edge by weight and walk the list, taking an edge whenever its endpoints are not already connected. Unlike Prim's, the partial result is a forest of separate trees that gradually merge. The only hard question — 'are these two vertices already connected?' — is exactly what Union-Find answers in near-constant time.

How to spot this pattern

Sort edges cheapest-first and take any that doesn't close a cycle — the classic greedy, with union-find providing the cycle test in near-constant time. The pairing is what matters: Kruskal is a sort plus a disjoint-set structure, and the DSU is what makes "would this create a cycle?" cheap enough for the greedy to be practical.

03

Approach

1

Sort edges by weight

Cheapest first. This is the greedy order, and the sort dominates the runtime at O(E log E).

2

Union-Find as the cycle test

find(u) == find(v) means both are already in the same tree, so the edge would create a cycle — skip it. Otherwise union them and take the edge.

3

Stop at V−1 edges

A spanning tree on V vertices has exactly V−1 edges. Finishing with fewer means the graph was disconnected and no spanning tree exists.

04

Solution & live demo

1def kruskal(n, edges):
2 parent = list(range(n))
3 def find(x):
4 while parent[x] != x:
5 parent[x] = parent[parent[x]] # path compression
6 x = parent[x]
7 return x
8 
9 total, used = 0, 0
10 for u, v, w in sorted(edges, key=lambda e: e[2]): # cheapest first
11 ru, rv = find(u), find(v)
12 if ru == rv: # same component -> cycle
13 continue
14 parent[ru] = rv # merge, take the edge
15 total += w
16 used += 1
17 if used == n - 1:
18 break
19 return total if used == n - 1 else None
05

Common pitfalls

Comparing vertices instead of their roots

✗ Wrong
if u == v: continue
✓ Right
ru, rv = find(u), find(v)
if ru == rv: continue

Two different vertices can already sit in the same component through earlier edges, and adding another edge between them closes a cycle. Only the component representatives reveal that — the raw endpoints never match.

Merging vertices rather than roots

✗ Wrong
parent[u] = v
✓ Right
parent[ru] = rv

Attaching a non-root breaks the forest: the old root of u's component still points elsewhere, so the two components never actually merge and later cycle tests give wrong answers.

Assuming an MST always exists

✗ Wrong
return total
✓ Right
return total if used == n - 1 else None

A disconnected graph has no spanning tree — the loop simply runs out of edges having used fewer than n - 1. Returning the accumulated weight reports a spanning forest as though it were a tree.

06

Edge cases

Disconnected graph

Fewer than V−1 edges are taken — report no MST.

Duplicate weights

Any consistent tie-break works; different MSTs may result, all of equal weight.

Self-loop

Endpoints share a root immediately — always skipped.

07

Complexity

Time
O(E log E)
Space
O(V)
Sorting dominates; Union-Find is near-constant per query.