Union-Find, also known as Disjoint Set Union (DSU), is a data structure for solving graph connectivity problems like checking whether two nodes are connected, detecting cycles, or grouping elements efficiently.
Using union find, we can easily tell whether two elements belong to the same group and if not, it lets us merge groups together.
In this chapter, I’ll cover:
Union-Find is a data structure that helps us manage a collection of elements divided into disjoint sets meaning no two sets overlap.
Loading simulation...
Every element belongs to exactly one set, and sets can be merged when a connection is discovered.
Union-Find supports two fundamental operations:
find(Alice) and find(Bob) will return the same root.The simplest way to represent Union-Find is with an array called parent.
parent array. Initially, every node is its own parent, meaning each element is its own setStep 1: Initialization
Step 2: Find Operation
Step 3: Union Operation
Consider 5 elements: [0, 1, 2, 3, 4].
union(0, 1), elements 0 and 1 share the same root.union(2, 3), elements 2 and 3 share the same root.find(1) and find(0), they’ll both return 0, meaning they’re in the same set.In this basic version:
The basic implementation of Union-Find works, but it can get slow if the parent pointers form tall chains. In the worst case, operations can take O(n) time.
To fix this, we use two optimizations: Path Compression and Union by Rank (or Size).
With both applied, find and union run in amortized O(α(n)) time, where α is the inverse Ackermann function. The bound is per-operation amortized, not worst-case: a single find may still walk a long chain, but the path compression it performs flattens the structure so the total cost of any sequence of m operations on n elements is O(m · α(n)). For every n that fits in memory, α(n) ≤ 4, so this is effectively constant on average.
Path compression flattens the structure of the tree whenever we call find.
find(x) climbs one parent at a time until it reaches the root.Consider a long chain of 10 nodes. Without path compression, find walks through all 10 nodes every time. With path compression, after one find call every node on that path points directly to the root, so later finds on those nodes run in O(1).
This optimization keeps the tree shallow when merging sets.
When path compression and union by rank are used together, find and union run in amortized O(α(n)) time per operation, which is effectively constant for any practical input size.
The naive implementation runs find and union in O(n) in the worst case, because the parent pointers can form a single tall chain that find must walk from end to root. Adding path compression and union by rank or size together changes this picture: each operation runs in O(α(n)) amortized, where α is the inverse Ackermann function. For any input size that fits in memory, α(n) stays at or below about 4, so each operation is effectively constant. A sequence of m operations on n elements runs in O(m · α(n)).
The space cost is O(n) for the parent array, plus another O(n) for the rank or size array, giving O(n) overall.
parent array where each element starts as its own parent, find walks up the parent chain to the root, and union points one root at the other; both run in O(h) time, which degrades to O(n) when the parent pointers form a tall chain.10 quizzes