并查集中包含 3 种基础操作,包括构建新的集合(MAKE-SET)、合并集合(UNION)和查找某个元素所在的集合(FIND-SET)。
设 x、y 分别为并查集中任意集合中的元素,则各操作详情如下:
1) MAKE-SET(x):构建新的集合
在初始化阶段,需要将元素构建成并查集结构。在此过程中,为所有的元素都建立一个独立的集合,每个新集合中仅包含一个元素,即对于 MAKE-SET(x) 过程,构建一个只包含 x 元素的集合。由于并查集中的各个集合不相交,因此,元素 x 不会出现在其他集合中。
2) UNION(x,y):合并两个集合
该过程中,将 x 元素所在的集合 Sx 和 y 元素所在的集合 Sy 合并为一个新的集合。为了保持并查集中各个集合互不相交的特性,需要在完成合并后删除原集合 Sx 和 Sy,同时,从新集合 Sx∪Sy中任意选取一个元素作为新集合的代表元素。
在实际操作中,为了提升执行效率,通常将其中一个集合并入另一个集合中来代替删除操作。
3) FIND-SET(x):查找某元素所在的集合
在该过程中,给定元素 x,需要返回一个指针,该指针指向包含 x 的集合的代表。
在实现过程中,维护两个数组分别保存各元素的所属集合的代表元素和集合的大小,分别用 fatherList 和 sizeList 表示:
MAKE-SET(x) 过程,初始化每个节点的代表元素为自身,每个节点各自组成一个集合;
FIND-SET(x) 过程,用递归的方式获取当前元素 x 所属集合的代表元素,同时在该过程中进行路径压缩;
UNION 过程,不断将两个集合进行合并,选择较大集合的代表元素作为新集合的代表元素,即修改较小集合中各个元素的代表元素信息,可减小改动量,提升操作效率。
并查集的 3 种基本操作代码:
class Union_Find_Set(object):
# 初始化
def __init__(self, input):
# 初始化两个列表
self.fatherList = {} # 保存元素所属集合的代表元素
self.sizeList = {} # 保存父节点包含的元素个数
for x in input:
self.make_set(x)
# MAKE-SET操作
# 将节点的父节点设为自身,size设为1
def make_set(self, x):
self.fatherList[x] = x
self.sizeList[x] = 1
# FIND-SET操作
# 采用递归的策略定位父节点
# 在父节点查找过程中,将当前节点连接到父节点上,进行路径压缩
def find_set(self, x):
father = self.fatherList[x]
if(x != father): # 递归定位父节点
father = self.find_set(father)
self.fatherList[x] = father # 路径压缩
return father
# UNION操作
# 将a和b两个集合合并在一起
def union(self, a, b):
if a is None or b is None:
return
a_father = self.find_set(a) # 获取两元素所在集合的代表元素
b_father = self.find_set(b)
if(a_father != b_father):
a_size = self.sizeList[a_father] # 获取两元素所在集合的大小
b_size = self.sizeList[b_father]
if(a_size >= b_size): # 将规模较小的集合合并到规模较大的集合下面
self.fatherList[b_father] = a_father
self.sizeList[a_father] = a_size + b_size
self.sizeList[b_father] = 0
else:
self.fatherList[a_father] = b_father
self.sizeList[b_father] = a_size + b_size
self.sizeList[a_father] = 0