并查集 Union Find 算法
定义
并查集(Disjoint-Set)是一种可以动态维护若干个不重叠的集合,并支持合并与查询两种操作的一种数据结构。
基本操作
- 合并(Union):合并两个集合。
- 查询(Find):查询元素所属集合。
具体实现
我们建立一个数组father_dict字典表示一个并查集,father_dict[i]表示i的父节点。并且设置一个size_dict字典,size_dict[i]表示i的后代节点的个数,包括其本身。
初始化:
每一个点都是一个集合,因此自己的父节点就是自己father_dict[i]=i,size_dict[i]=1.
查询:
每一个节点不断寻找自己的父节点,若此时自己的父节点就是自己,那么该点为集合的根结点,返回该点。
合并:
合并两个集合只需要合并两个集合的根结点,size_dict大吃小,为了尽可能的降低树高。
路径压缩:
实际上,我们在查询过程中只关心根结点是什么,并不关心这棵树的形态(有一些题除外)。因此我们可以在查询操作的时候将访问过的每个点都指向树根,这样的方法叫做路径压缩,单次操作复杂度为O(logN)。
路径压缩
具体实现:
python
def Find(self, x):
root = self.father_dict[x]
# 路径压缩
while root != self.father_dict[root]:
root = self.father_dict[root]
while x != root:
x, self.father_dict[x] = self.father_dict[x], root
return root
防止树的退化
python
if self.size_dict[x_father] > self.size_dict[y_father]:
self.father_dict[y_father] = x_father
self.size_dict[x_father] += self.size_dict[y_father]
else:
self.father_dict[x_father] = y_father
self.size_dict[y_father] += self.size_dict[x_father]
具体实现代码
python
class UnionFindSet:
def __init__(self, n):
self.father_dict = {}
self.size_dict = {}
for i in range(n):
self.father_dict[i] = i
self.size_dict[i] = 1
def Union(self, x, y):
x_father = self.Find(x)
y_father = self.Find(y)
if x_father == y_father:
return
if self.size_dict[x_father] > self.size_dict[y_father]:
self.father_dict[y_father] = x_father
self.size_dict[x_father] += self.size_dict[y_father]
else:
self.father_dict[x_father] = y_father
self.size_dict[y_father] += self.size_dict[x_father]
def Find(self, x):
root = self.father_dict[x]
# 路径压缩
while root != self.father_dict[root]:
root = self.father_dict[root]
while x != root:
x, self.father_dict[x] = self.father_dict[x], root
return root