这一阵子在做leecode题的时候出现了太多的并查集,所以趁此机会想系统性的总结一下相关的知识,以便帮助大家更好的理解。如果有错误希望大家指正
并查集的介绍
并查集是在多集合问题中,刚开始时将每个元素构成一个单元素的集合,然后按照一定的顺序将属于同一组的元素进行合并。在此期间要反复查找一个元素在哪个集合中。
总之,并查集是处理一些不相关集合的合并及查询问题的一种树形的数据结构(与它的名字很相符是不是,哈哈)
并查集的理解
为了帮助大家更好的理解,我采用一个比喻来介绍
以武侠小说中的帮派为例,在刚开始时每个人都建立一个帮派,那么他们自己就是帮派的代表人物。(如下图所示)
之后帮派之间会进行争斗,一些强的帮派会吞并一些弱的帮派,那么弱的帮派也就附属于强的帮派(1和3进行争斗,假设胜者为1)
假设之后2再和3较量时,3表示拒绝,并说我不和你较量,你要和帮派老大较量,如果2输给1,同时456之间也进行较量,假设较量之后结果如下:
4和1进行较量时,如果4输给1,那么就会演变成下图:
以上,就是并查集功能的体现。
并查集的相关功能的python实现
由定义可知,并查集的功能主要是查询和合并。所以,一般会有三个步骤。
初始化
初始化是将每个元素看作一个集合,并将元素本身作为集合中的代表元素。
就相当于上面例子中的每个人建立自己帮派的过程,此时,每个帮派的代表元素都是他自己
n = 64
parents = [0]*64
for i in range(n):
parents[i] = i
假设有64个元素,我们使用一个等长的列表来存储每个元素所属列表的代表元素
查询
查询过程就是查询元素所在集合的代表元素的过程。
相当于上面例子中的帮派之间争斗时,需要找到小弟的大哥来进行比较
def find(x):
if parents[x] == x:
return x
else:
return find(parents[x])
在这个函数中使用了递归的思想去找到根节点,也就是例子最后的1
合并
合并的过程就是将属于相同集合的元素进行合并的过程。相当于例子中的帮派的吞并过程
先找到两个集合的代表元素,将前者的父节点设为后者即可
def unite(x,y):
parents[find(x)] = find(y)
结语
这是我看大神的介绍理解的一般的并查集的思路。其实,这种最基本的并查集的思路还可以进一步的优化,如进行路径压缩和按照树的深度来选择合并的方式,以便降低时间复杂度
如果有错误希望大家指正,我会立即修改。
希望对你有所帮助
(附上大神所发布的链接https://zhuanlan.zhihu.com/p/93647900)