Union-Find (Disjoint Set)

Context: FIT2004_MOC · maintains a partition of elements under merging, answering “are these two in the same set?” in near-constant time — the cycle test that makes Kruskal fast Parent Framework: Set (ADT)

Quick Revision

  • 🎯 Objective: two operations only ➔ find(u) returns ‘s representative, union(u,v) merges the two sets; same representative same set.
  • 📦 Core Components: one parent array ➔ positive parent index, negative root, magnitude size (or rank) | union-by-size/rank ➔ height | path compression ➔ re-parents the whole find path to the root.
  • ⚡ Key Constraint: a negative entry is meaningful only at a root — reading a non-root’s magnitude as a size is the single highest-frequency hand-trace error.

📝 How It Works

1. The Two Operations

  • Represent each set as a Tree ➔ the set’s identity is its root; the whole structure is a Forest, one tree per set.
  • find(u) ➔ walk parent upward until the entry is negative; that index is the representative. Cost height.
  • union(u,v) ➔ find both; equal roots ⟹ refuse (already merged), otherwise point one root at the other.
  • Why it fits Kruskal ➔ edge closes a cycle iff already share a root, so the cycle test is find(u) == find(v), and accepting the edge is the union.

2. The Array Encoding

  • One array, two meanings ➔ parent[i] >= 0 ⟹ index of ‘s parent; parent[i] < 0 ⟹ is a root and is its size (or its rank/height, depending on the heuristic chosen).
  • Initialisation ➔ every entry : singleton trees of size , height .
  • No pointers, no objects ➔ space total, cache-friendly, and the state fits on one exam line.
  • Root bookkeeping is the whole update ➔ a union writes exactly two cells: the losing root’s parent, and the winning root’s negative counter.

3. Heuristic 1 — Union by Size (prep P3)

  • Rule ➔ the tree with fewer elements is appended beneath the root of the larger; on a tie the unit’s convention makes the first argument’s root the new root.
  • New counter ➔ .
  • Guarantee ➔ ⟹ (proof in Applied Exercise) ⟹ every find and union is .
  • Why it works ➔ a node’s depth only increases when its whole tree is the smaller side, which at least doubles the set it belongs to; a node can be doubled at most times.

4. Heuristic 2 — Union by Rank, and Path Compression (applied P11)

  • Union by rank/height ➔ store the height instead of the size and append the shorter tree; the height grows only when the two heights are equal. Targets the quantity that find actually pays for, so it keeps trees at least as shallow as union-by-size — often shallower.
  • Path compression ➔ after a find, re-point every node on the walked path directly at the root. Costs nothing extra asymptotically (the path is already traversed) and permanently flattens it.
  • It fires even on a refused union ➔ union(8,3) with already in the same set performs no merge, but the two find calls still compress both paths — a rejected edge in Kruskal still speeds up the rest of the run.
  • Rank is then a bound, not a height ➔ compression shortens paths without updating ranks, so the stored rank becomes an upper bound on the true height. This is why the pair is rank + compression, never size + compression bookkeeping.
  • Result ➔ amortised cost per operation is almost ; the combination is what turns Kruskal’s cycle testing into a non-bottleneck.

🔭 Beyond the lecture (not in the slides): the exact amortised bound for union-by-rank path compression is , the inverse Ackermann function, for any writable in this universe. FIT2004 asks only for "almost constant"; the full disjoint-set analysis is FIT3155 material.

⚙️ Core Implementation

🔹 Parent array, union by size

🔹 Path compression

⚖️ Complexity

elements, at most successful unions.

VariantfindunionAll unionsExtra state
Naive parent arraynone — degenerates to a chain
Lecture’s set list map array (copy a set, rewrite the map) lists map
Same, smaller into larger worst, amortisedas above
Union by size or rank array only
Union by rank path compressionalmost amortisedalmost amortisedalmost array only
  • Worst case is a sequence bound ➔ a single compressed find can still cost ; only the amortised figure is near-constant ➔ FIT2004 Unit Cheatsheet §1️⃣ amortised is a guarantee, not a probability.
  • Space is always auxiliary ➔ one integer array, no recursion in the iterative form.
  • At most unions ever succeed ➔ each successful union reduces the component count by one, from to ; every further call is a refused query.

📊 Exam Execution Trace & Applied Exercises

Prep P3 — elements, all parent[i] = -1, union by size, first argument wins ties.

Manual Execution Trace

OpRoots found (size)Actionparent[0..9]
init— singletons-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
union(1,5) tie under -1 -2 -1 -1 -1 1 -1 -1 -1 -1
union(2,7) tie under -1 -2 -2 -1 -1 1 -1 2 -1 -1
union(4,8) tie under -1 -2 -2 -1 -2 1 -1 2 4 -1
union(5,8) tie under -1 -4 -2 -1 1 1 -1 2 4 -1
union(6,7) under -1 -4 -3 -1 1 1 2 2 4 -1
union(6,0) under 2 -4 -4 -1 1 1 2 2 4 -1
union(2,3) under 2 -4 -5 2 1 1 2 2 4 -1
union(4,0) under 2 2 -9 2 1 1 2 2 4 -1
union(8,3) samerefused(unchanged)
union(9,0) under 2 2 -10 2 1 1 2 2 4 2

Final Extracted Output: one tree rooted at (size ): children , , ⟹ height . Under union-by-rank path compression the same sequence finishes at height — the shallower shape is the point of the exercise.

  • Read the trap ➔ union(5,8) merges the trees of the roots of and , not the elements themselves; the tie is broken on the first argument’s root (), not on the smaller index.

Applied Exercise — the union-by-size height bound (P8)

Problem: prove for every root built by union-by-size, then bound one union and all unions.

Final Extracted Output: a union costs ; at most unions ever succeed (each drops the component count by one) ⟹ all unions cost .

⚠️ Common Mistakes

  • 💡 Reading a size off a non-root ➔ only negative entries carry sizes. Always find first, compare the roots’ counters, then write.
  • 💡 Unioning the arguments instead of their roots ➔ parent[v] = u corrupts the forest; it must be parent[root_v] = root_u.
  • 💡 Claiming path compression alone gives near-constant time ➔ the near-constant bound needs both heuristics; compression on top of an unbalanced union still permits deep trees before the first find reaches them.

🧠 Active Recall