Problem. (Disjoint Set) Consider a collection of pairwise disjoint sets DS:={S1,S2,…,Sr}, where each set Si contains a single representative Rep[Si]∈Si. Suppose DS supports the following operations:
Make-Set(x): Adds {x} to DS, with Rep[{x}]=x.
Find-Set(x): Returns Rep[S(x)], where S(x) is the set containing x.
Union(x,y): Replaces S(x) and S(y) with S(x)⊔S(y) and sets Rep[S(x)⊔S(y)] to Rep[S(x)] or Rep[S(y)].
This data structure is called the Union Find data structure.
The idea is to say each set is a doubly-linked list. For example,
DS={{3,9,4},{2,7,1,8}}⟹{3↔9↔4} and {2↔7↔1↔8}.
So each element in each Si has a prev and next pointer. And we'll say Rep[Si] is the head of Si.
Solution. (Disjoint Set #1) If every Si is a doubly-linked list, then:
Make-Set(x): Trivial.
Find-Set(x): Repeatedly follow prev pointers until you reach the head.
Union(x,y): Use prev and next to find the head and tail of S(x) and S(y), respectively. Link them.
But this is a little silly. It shouldn't take Θ(∣S(x)∣) just to find the head; S(x) can just store the head in metadata.
Solution. (Disjoint Set #2) Every element now furthermore points to a metadata object pointing to the head.
Make-Set(x): Trivial, still Θ(1).
Find-Set(x): Now also trivially Θ(1), since you can just read the metadata.
Union(x,y): Now Θ(∣S(y)∣), because you need all elements in S(y) to point to new metadata.
But we can do even better by considering an amortized analysis.
Definition (Amortized Cost). A data structure D has an amortized cost of T if any sequence of k operations starting from the initial state of D has a total cost at most k⋅T.
Solution. (Disjoint Set #3) Let's be smarter about handling Union(x,y): always merge so that ∣S(y)∣≤∣S(x)∣. We claim this yields an amortized cost of Θ(logn), where n:=∑i=1r∣Si∣.
Proof: Any individual element has its pointer updated at most O(logn) times, so Union steps take at most O(nlogn) time. Every other step takes Θ(1) time. And k≥n. ■
More generally, there are three strategies for computing amortized cost.
Aggregate Method: What we did just now. Just compute the cost as a function of k, then divide by k.
Accounting Method: We'll discuss this in recitation!
Potential Method: Define a potential function Φ:DS→R≥0, with Φi:=Φ(DSi), forced to satisfy Φ0=0.
Suppose the real costs of k operations are c1,c2,…,ck. Define fake cost by ci^:=ci+Φi−Φi−1. Note that:
So the Union operation also has amortized cost O(logn).
And so this solution also has O(logn) amortized cost overall. ■
It turns out that if you combine the approaches of Disjoint Set #5 and Disjoint Set #6, you get a solution with O(α(n)) amortized cost, where α is the Inverse-Ackermann Function. For most reasonable n, we have α(n)≤4.