算法学习|并查集
并查集(Union-Find)
高效处理不相交集合的合并与查询问题
- 判断两个元素是否属于同一集合
- 合并两个集合
- 动态连通性问题(如网络连接、图论中的连通分量)
算法思想
- 树结构表示集合:每个集合用一棵树表示,根节点为集合的代表。
- 路径压缩(Path Compression):在查找根节点时,将路径上的节点直接连接到根节点,降低树的高度。
- 按秩合并(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连通)

浙公网安备 33010602011771号