data-structure

what

a.k.a: disjoint set

implementation

functional

parent = list(range(n))
rank = [1] * n
 
def find(u, parent):
    while u != parent[u]:
        parent[u] = parent[parent[u]]
        u = parent[u]
 
    return u
 
def union(u, v, parent, rank):
    pu = find(u, parent)
    pv = find(v, parent)
    
    if pu == pv:
        return
 
    parent[pu] = pv
    
    # if rank[pu] > rank[pv]:
    #     parent[pv] = pu
    # elif rank[pu] < rank[pv]:
    #     parent[pu] = pv
    # else:
    #     parent[pu] = pv
    #     rank[pv] += 1
    
    # if rank[pu] > rank[pv]:
    #     parent[pv] = pu
    #     rank[pu] += rank[pv]
    # else:
    #     parent[pu] = pv
    #     rank[pv] += rank[pu]

oop

class UnionFind:
    def __init__(self, n: int):
        # Initialize parent and rank arrays
        self.parent = list(range(n))
        self.rank = [0] * n
 
    def find(self, x: int) -> int:
        # Find the parent of node x. Use Path Compression
        while x != self.parent[x]:
            self.parent[x] = self.parent[self.parent[x]]
        return x
 
    def unite(self, x: int, y: int) -> None:
        # Unite two nodes x and y, if they are not already united
        px = self.find(x)
        py = self.find(y)
        if px == py:
            return
        
        self.parent[px] = py
 
        # # Union by Rank Heuristic
        # if self.rank[px] > self.rank[py]:
        #     self.parent[py] = px
        # elif self.rank[px] < self.rank[py]:
        #     self.parent[px] = py
        # else:
        #     self.parent[py] = px
        #     self.rank[px] += 1
 
        # # Union by Count Heuristic
        # if self.rank[px] > self.rank[py]:
        #     parent[py] = px
        #     rank[px] += rank[py]
        # else:
        #     parent[px] = py
        #     rank[py] += rank[px]
 
    def is_connected(self, x: int, y: int) -> bool:
        # Check if two nodes x and y are connected or not
        return self.find(x) == self.find(y)