Disjoint Sets

Week 12, Monday

March 23, 2026

Announcements

  • PA3 due Week 12
  • PEX5 this week!

A Disjoint Sets Example

Let R be an equivalence relation on the set of students in this room, where (s, t) ∈ R if s and t have the same favorite among {AC, FN, FB, TR, CC, CR, PMC, ___}.

2 5 9 7 0 1 4 8 3 6

Operations We’d Like to Facilitate

  1. find(4)
  2. find(4) == find(8)
  3. if find(7) != find(2): union(find(7), find(2))

Disjoint Sets ADT

We will implement a data structure in support of “Disjoint Sets”:

  • Maintains a collection S = {s0, s1, … sk} of disjoint sets.
  • Each set has a representative member.
  • Supports functions:

 

make_set(k) — creates a new set containing only k

union(k1, k2) — merges the sets containing k1 and k2

find(k) — returns the representative of the set containing k

A First Data Structure for Disjoint Sets

0 1 4 2 7 3 5 6
0 1 2 3 4 5 6 7 0 0 2 3 0 3 3 2

 

Find: __________

Union: __________

A Better Data Structure: UpTrees

  • If array value is -1, then we’ve found a root; otherwise value is the index of the parent.
  • x and y are in the same uptree iff they are in the same set.
0 1 2 3 0 1 2 3
0 1 2 3 0 1 2 3
0 1 2 3 0 1 2 3
0 1 2 3 0 1 2 3

Example: Partition of Elements into Disjoint Sets

2 5 9 7 0 1 4 8 3 6
5 9 2 7 4 0 8 1 3 6 0 1 2 3 4 5 6 7 8 9 4 8 5 6 -1 -1 -1 -1 4 5

UpTree Implementation

def find(self, i):
    if self.s[i] < 0:
        return i
    else:
        return self.find(self.s[i])


Running time depends on ___________.

Worst case? ___________

What’s an ideal tree? ___________


def union(self, root1, root2):
    self.s[root2] = root1

Smart Unions

7 6 8 9 0 1 2 3 4 10 5 11 Union by ____________: 0 6 1 6 2 6 3 8 4 5 10 6 7 7 8 7 9 7 10 4 11 5 Keeps overall height of tree as small as possible. Union by ____________: 0 6 1 6 2 6 3 8 4 5 10 6 7 7 8 7 9 7 10 4 11 5 Increases distance to root for fewest nodes.

Both of these schemes for Union guarantee the height of the tree is ________.

Smart Unions: Implementation

def find(self, i):
    if self.s[i] < 0:
        return i
    else:
        return self.find(self.s[i])


def union_by_size(self, root1, root2):
    new_size = self.s[root1] + self.s[root2]
    if self.s[root1] <= self.s[root2]:   # root1 is bigger (more negative)
        self.s[root2] = root1
        self.s[root1] = new_size
    else:
        self.s[root1] = root2
        self.s[root2] = new_size

Summary

UpTree implementation of ADT Disjoint Sets with smart Union gives:

  • Find: \(O(\log n)\)
  • Union: \(O(1)\)

 

Can we do better?