并查集的两种优化(按秩合并,路径压缩)

并查集是建立在对不相交集合进行的两种基本操作的基础之上的。操作之一:检索某元素属于哪个集合;操作之二:合并两个集合。黑书上说了,这种结构显然可以用链表或森林实现,显然用链表进行查询时间复杂度应该是O(n)级别的,而使用森林进行查访如果处理的好时间复杂度就应该是O(logn)。对于用森林来实现并查集,黑书上有句加点话我同样认为很重要“用树根来标识一个集合”。于是对于并查集就存在这么两个很关键的优化操作:第一,让深度小的数成为深度较大的树的子树,这个优化成为启发式合并,这样做之后树的深度为O(logn);第二,找到u所在的树根v以后,把从u到v的路径上所有点的父亲都设置为v,这个优化称作路径压缩。既然第一个优化叫做启发式合并,那么很重要的就是启发式函数的选取,一般可以用树的深度作为启发函数值,但由于路径压缩优化,树的深度是在不断变化的。这时候便可引入一个秩,按我的理解就是一颗树收取与其等秩的树的次数,因为合并的最底层操作就是两个独立元素的合并,所以rank越大,树中的元素越多,显然rank的初值都是0。

1) 按秩合并:

按秩合并的基本思想是使包含较少结点的树德根指向包含较多结点的树的根,而这个树的大小可以抽象为树的高度,即高度小的树合并到高度大的树,这样资源利用更加合理。
     为了实现一个按秩合并的不想交集合森林,要记录下秩的变化。对于每个结点x,有一个整数rank[x],它是x的高度(从x到其某一个后代叶结点的最长路径上边的数目)的一个上界。(即树高)。当由MAKE-SET创建了一个单元集时,对应的树中结点的初始秩为0,每个FIND-SET操作不改变任何秩。当对两棵树应用UNION时,有两种情况,具体取决于根是否有相等的秩。当两个秩不相等时,我们使具有高秩的根成为具有较低秩的根的父结点,但秩本身保持不变。当两个秩相同时,任选一个根作为父结点,并增加其秩的值路径压缩。

2)路径压缩:

是在FIND-SET操作中,把查找路径上的每个结点都直接指向根结点。路径压缩并不改变结点的秩。关于路径压缩,看图理解,之间为FIND-SET操作前集合,之后为FIND-SET操作后集合。此时,查找路径上的每一个结点都直接指向根。
路径压缩代码实现方式有两种:递归式和非递归式。
1)递归方式
伪代码:
FIND-SET(x)

1  if x ≠ p[x]

2     then p[x] ← FIND-SET(p[x])

3  return p[x]

    原文作者:犯罪团伙问题
    原文地址: https://blog.csdn.net/ccsu_cherish/article/details/9750683
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞