Knowledge / Computer Science and Engineering / Disjoint set union

Disjoint set union

Computer Science and Engineering (B.E./B.Tech) · Data structures · free study notes for exams, placements and interviews

In short

A disjoint-set union (DSU) or union-find structure maintains a partition of n elements into non-overlapping sets and supports two operations - find(x) (which set does x belong to) and union(a,b) (merge the two sets). It is the standard way to answer "are these two things already connected?" while connections keep arriving, which is why it sits inside Kruskal's minimum spanning tree algorithm, cycle detection in undirected graphs and connected-component labelling. With union by rank/size plus path compression, m operations on n elements cost O(m·α(n)), where α is the inverse Ackermann function and is at most 4 for any input that fits in a computer - effectively constant time. It is examined in GATE CS (programming and data structures, greedy algorithms/MST), in university data-structures and design-and-analysis-of-algorithms papers, and is a frequent coding-round question at Amazon India, Microsoft IDC, Google India, Flipkart, Zoho, Samsung R&D, Media.net and in TCS Digital/CodeVita-style contests.

Explained

What the structure is and what it must support

Representations, from naive to forest

Heuristic 1 - union by rank or by size

Heuristic 2 - path compression

Complexity and the analysis, in outline

Variants and extensions commonly examined

Classic algorithms built on DSU

Key points

Formulas and examples

components = n − (number of successful unions); a union is "successful" iff find(a) ≠ find(b)
A tree whose root has rank r has ≥ 2r nodes ⇒ rank ≤ ⌊log₂ n⌋ ⇒ find is O(log n) with balancing alone
Time for m operations on n elements (union by rank + path compression) = O(m · α(m,n)), α = inverse Ackermann, α(n) ≤ 4 in practice
Hopcroft–Ullman form: O((m + n) · log\* n), log\* n = 1 + log\*(log₂ n) for n > 1, log\* n = 0 for n ≤ 1; log\*(10⁶) = 5
Quick-find: find O(1), union O(n) ⇒ n−1 unions = O(n²); Quick-union unbalanced: find O(n) worst case
Kruskal: O(E log E + E·α(V)) ≈ O(E log E); edges in MST of a connected graph = V − 1
Weighted DSU: pot[x] = value(x) − value(root(x)); value(x) − value(y) = pot[x] − pot[y] when root(x) = root(y)
int p[N], sz[N], comps;
void init(int n){ comps=n; for(int i=0;i<n;i++){ p[i]=i; sz[i]=1; } }
int find(int x){ while(p[x]!=x){ p[x]=p[p[x]]; x=p[x]; } return x; }   // path halving
bool unite(int a,int b){
    a=find(a); b=find(b);
    if(a==b) return false;                 // same set -> this edge closes a cycle
    if(sz[a]<sz[b]) std::swap(a,b);        // union by size
    p[b]=a; sz[a]+=sz[b]; --comps;  return true;
}
// recursive full compression:  int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }
// weighted DSU:  int find(int x){ if(p[x]==x) return x; int r=find(p[x]); d[x]+=d[p[x]]; p[x]=r; return r; }

Example 1 - trace the parent array (typical GATE/university question). n = 8, elements 0…7, union by size (ties: second root attached under the first), path compression on find.

OperationRoots foundActionparent changessizes
union(1,2)1, 2tie → 2 under 1p[2]=1sz[1]=2
union(3,4)3, 4tie → 4 under 3p[4]=3sz[3]=2
union(5,6)5, 6tie → 6 under 5p[6]=5sz[5]=2
union(1,3)1, 3tie (2,2) → 3 under 1p[3]=1sz[1]=4
union(5,7)5, 72 > 1 → 7 under 5p[7]=5sz[5]=3
find(4)path 4→3→1compressp[4]=1-
union(2,6)1 (sz 4), 5 (sz 3)5 under 1p[5]=1sz[1]=7

Example 2 - Kruskal's MST on a 6-city fibre network. Vertices A–F; edge costs in ₹ lakh. Edges: B-C 2, D-E 2, C-D 3, E-F 3, A-B 4, A-C 4, C-E 4, B-D 6, D-F 7 (already sorted).

EdgeCostfind endpointsDecisionRunning totalComponents
B-C2B, C differaccept25
D-E2D, E differaccept44
C-D3{B,C} vs {D,E}accept73
E-F3{B,C,D,E} vs Faccept102
A-B4A vs {B,C,D,E,F}accept141
A-C4same rootreject (cycle)141

Example 3 - why the heuristics matter, with numbers. n = 10⁶ elements, m = 5×10⁶ operations.

Example 4 - weighted DSU consistency check (relative salaries, ₹). Statements, processed in order:

  1. value(2) − value(1) = 500 - different roots → attach root 2 under root 1 with pot[2] = 500.
  2. value(3) − value(2) = 300 - find(2) gives root 1 with pot 500 → attach 3 under 1 with pot[3] = 500 + 300 = 800.
  3. Query value(3) − value(1): same root, pot[3] − pot[1] = 800 − 0 = ₹800 - consistent with the claim 800.
  4. value(4) − value(1) = 200 → attach 4 under 1 with pot[4] = 200.
  5. Claim value(4) = value(3) − 600: check pot[4] − pot[3] = 200 − 800 = −600 ✓ consistent.
  6. Claim value(2) − value(3) = 100: pot[2] − pot[3] = 500 − 800 = −300 ≠ 100 → contradiction, statement rejected.

Example 5 - bipartite check with the 2n trick. Graph on {1,2,3} with edges (1,2), (2,3), (3,1); DSU over 6 nodes where i+3 is "opposite colour of i".

Schemefindunionn−1 unions + m findsNotes
Quick-find (labels)O(1)O(n)O(n² + m)good when unions are rare
Quick-union, unbalancedO(n)O(1)*O((n+m)·n)degenerates to a path
Union by rank/size onlyO(log n)O(log n)O((n+m) log n)worst-case guarantee; supports rollback
Path compression onlyamortized O(log n)O(1)*O(n + m log n)no rank array needed
Rank/size + compressionO(α(n)) amortizedO(α(n))O((n+m)·α(n))standard choice

(*after the two finds)

Where it is used

Interview questions

Common mistakes

Related topics

Open in the Knowledge reader →Find jobs →