算法学习|并查集

并查集(Union-Find)

高效处理不相交集合的合并与查询问题

  • 判断两个元素是否属于同一集合
  • 合并两个集合
  • 动态连通性问题(如网络连接、图论中的连通分量)

算法思想

  1. 树结构表示集合:每个集合用一棵树表示,根节点为集合的代表。
  2. 路径压缩(Path Compression):在查找根节点时,将路径上的节点直接连接到根节点,降低树的高度。
  3. 按秩合并(Union by Rank):合并两棵树时,将较小的树合并到较大的树下,避免树过高。

算法流程

1. 初始化

每个元素的父节点初始化为自己,秩(树的高度)初始化为0。

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))  # parent[i] 表示i的父节点
        self.rank = [0] * n           # rank[i] 表示以i为根的树的高度

2. 查找(Find)

找到元素的根节点,并进行路径压缩。

def find(self, x):
    if self.parent[x] != x:
        self.parent[x] = self.find(self.parent[x])  # 路径压缩
    return self.parent[x]

3. 合并(Union)

合并两个元素所在的集合,按秩合并优化。

def union(self, x, y):
    root_x = self.find(x)
    root_y = self.find(y)
    if root_x == root_y:  # 已在同一集合,无需合并
        return
    # 按秩合并:小树合并到大树
    if self.rank[root_x] < self.rank[root_y]:
        self.parent[root_x] = root_y
    else:
        self.parent[root_y] = root_x
        if self.rank[root_x] == self.rank[root_y]:
            self.rank[root_x] += 1

时间复杂度

路径压缩和按秩合并后为\(o(1)\)
否则退化为\(o(n)\)


代码

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n
    
    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])  # 路径压缩
        return self.parent[x]
    
    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        if root_x == root_y:
            return
        if self.rank[root_x] < self.rank[root_y]:
            self.parent[root_x] = root_y
        else:
            self.parent[root_y] = root_x
            if self.rank[root_x] == self.rank[root_y]:
                self.rank[root_x] += 1

# 示例:判断网络是否全连通
n = 5
edges = [(0,1), (1,2), (3,4)]
uf = UnionFind(n)
for u, v in edges:
    uf.union(u, v)
# 检查是否所有节点连通
root = uf.find(0)
all_connected = all(uf.find(i) == root for i in range(n))
print(all_connected)  # 输出 False(0-1-2连通,3-4连通)
posted @ 2025-04-20 15:26  lumiere_cloud  阅读(59)  评论(0)    收藏  举报