UnionFind

2024-10-11

UnionFind is one of my favorite algorithms. Here, I go into the code for implementing it.

class UF:
    def __init__(self, size: int):
        self.size = size
        self.parent = [i for i in range(size)]
        self.component_sizes = [1 for _ in range(size)]
        self.num_components = size

    def find(self, p: int) -> int:
        """
        Find the root of the node and do path compression along the way.
        :param p: node which you want to find the root of
        :return: root node of the component to which `p` belongs
        """
        root = p
        while root != self.parent[root]:
            root = self.parent[root]
        current = p
        while current != root:
            nxt = self.parent[current]
            self.parent[current] = root
            current = nxt
        return root

    def connected(self, p: int, q: int) -> bool:
        return self.find(p) == self.find(q)

    def component_size(self, p: int) -> int:
        return self.component_sizes[self.find(p)]

    def unify(self, p: int, q: int):
        if self.connected(p, q):
            return
        r1 = self.find(p)
        r2 = self.find(q)

        smaller, larger = sorted([r1, r2], key=lambda x: self.component_sizes[x])
        self.component_sizes[larger] += self.component_sizes[smaller]
        self.parent[smaller] = larger
        self.component_sizes[smaller] = 0

        self.num_components -= 1