Module A-3·16 min read

Disjoint set union with path compression and union by rank — near-O(1) connectivity tracking.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module A-3 — Union-Find: Path Compression and Union by Rank

What this module covers: Every structure so far answers "what's the smallest/largest" or "how do I traverse this." Union-Find answers a different question entirely: are these two things connected, directly or transitively? This module covers the naive approach's hidden O(n) cost, and the two independent optimizations — path compression and union by rank — that together make Union-Find's operations run in almost constant time.


The Question: Connectivity, Not Order

Given a set of elements, some of which are connected to each other (directly or through a chain of connections), Union-Find answers two operations efficiently: find(x) — which connected group does x belong to? — and union(x, y) — merge x's group and y's group into one. Neither operation cares about ordering values or finding a maximum; it only cares about group membership.


The Naive Approach's Hidden Cost

The obvious implementation: an array mapping each element to its current group ID.

typescript

find is O(1) here, which looks great — but union has to relabel every single element currently in one of the two groups being merged, an O(n) scan in the worst case. Merging groups repeatedly (which is the entire point of Union-Find) means paying that O(n) cost on every single union — for n unions, that's O(n²) overall, the same quadratic trap flagged repeatedly throughout this course.


The Tree-Based Fix: Point to a Parent, Not a Group Label

Instead of storing a group label, store a parent pointer for each element — following parent pointers upward eventually reaches a root, which serves as that group's representative identity. union becomes cheap: just attach one root under the other, no relabeling of every member required.

typescript

This trades the naive approach's cost around: union is now cheap (find the two roots, attach one), but find can be expensive — if trees are allowed to grow into long chains (attaching root Y under root X repeatedly, always the same direction, can produce a straight-line tree), find degenerates to O(n), the exact same degeneration risk flagged for BSTs in Module P-5 and quicksort in Module P-10: a strategy that's efficient in general can become linear-chain-like under specific, unlucky sequences of operations.


Optimization 1: Path Compression

While walking up to find the root, re-point every node visited directly to the root, flattening the tree for every future find call on any of those nodes:

typescript

The recursive call finds the true root; the assignment afterward re-parents x (and, because of the recursion, every node along the original path) directly to that root, instead of leaving the original chain of intermediate parents in place. The next find call on any of those nodes is now O(1) instead of walking the original chain — this is a genuinely self-improving structure: every find call makes future find calls on the same nodes cheaper, a flattening effect that compounds across repeated use.


Optimization 2: Union by Rank

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.