Disjoint set(并查集) data structure

不相交集合(disjoint-set datastructure)数据结构又被称为并查集(union-find data structure)数据结构。 

涉及到将n 个不同的元素分成一组不相交的子集合(disjoint subset)。  所谓的不相交(disjoint), 又被称为nonoverlapping subset。 并查集(亦称为不相交集合) support 2个重要的operations:

 (1)Find (x)操作: 寻找给定的元素属于哪一个(唯一的)子集合。 这个Find 操作的返回的含有x的子集合S中 一个能够代表这个子集合S的item(一般是S的最小的成员)。 我们可以通过比较2个Find 操作, 即find(x) 和 find(y) 来比较x 和 y 是否在同一个子集合中。

(2)Union 操作: 将两个subset 合并成一个更大的subset。


除了上述的两个操作, 还有一个操作叫做makeSet(x), 该操作的作用是建立一个新的集合, 它的唯一的成员(因而为代表)是x。因为各个集合是不相交的, 所以x 不会出现在别的集合中。


具有上述三个重要的关于并查集合的操作, 那么众多的partition problem 都能够得到解决。




创建一个disjoint-set data structure 的最简单的方法就是对于每一个set, 我们用linked list 实现它。 每一个list  的head 的element  作为代表代表着这个list(当然也就是代表着这个subset)。 

 makeSet 操作就是创建一个具有one element的 list 。 Union 操作就是将2个list 合并称为一个list。 这是一个时间复杂度为O(1)的操作(constant-time operation)。

然而使用链表去实现每一个子集合的缺点就是导致Find 操作的时间复杂度为O(n)。 


不相交集合森林(disjoint-set forests)

所谓的Disjoint-set forest, 就是将每一个set 用树结构(tree data structure)(不一定是二叉树, 也可能是多叉树) 实现(represented。 树的每一个节点都holds a reference to its parrent node。 这是由 Bernard A. Galler and Michael J. Fischer 在1964年发明的。


在disjoint-set forest中, 每一个set 的representative 就是由这个set而创建起来的树的根节点, Find 操作 是沿着parent nodes, 直至到达the root。 Union 是将一棵树的根节点和另一棵树的根节点合并起来。 组成一棵更大的树。

相关的操作的实现过程如下:



上面使用树, 树的每个成员均指向它的父节点, 且每棵树根是这棵树的代表, 并且是其自己的父节点。 但是使用树的这种表示的 直接算法并不比使用链表 的直接算法快, 因为我们建的树的结构 是一棵高度不平衡(highly unbalanced)的树,  但是通过引入两种启发式的策略(“按秩合并”(Union by rank) 和 “路径压缩”(path compression)), 我们可以得到一种渐进最优的 不相交集合 数据结构。


(1)策略一: 按秩合并(Union by rank)

这个方法是将一棵较小树(即节点数少)的根结点 连接到 具有较大的树的根节点上(attach the smaller tree to the root of the larger tree)。  因为影响各个操作(算法)的是树的深度, 所以将较小的树添加到更深的树的根上 并不会增加秩除非这两个数的深度相同(秩会增加1)。

之所以使用“秩”这个术语而不是用“深度”, 是因为如果同时使用了路径压缩的策略, 秩 将不会与高度相同。 氮元素的秩 定义为0。 两棵秩同为r 的树合并为一个大树的时候, 他们的秩为r + 1. 只使用按秩合并这个策略, 将会使得makeSet 和 Union 以及 Find 操作的最坏情况下的时间复杂度为O(logn)。 优化后的makeSet 和 Union 的伪代码如下:



第二个优化算法被称为“路径压缩”。 这个优化策略是, 每当我们对树结构执行Find操作的时候, 我们就使用路径压缩策略对flattening the structure of the tree 。 关键是在路径上的每个节点都可以直接连接到根上。 为了达到扁平化树结构的效果, Find 向上递归的traverse树, 改变每一个节点的引用(parent Reference)到根节点()root。 最终我们会得带一个much flatter 的树。 对以后直接或者间接的引用这些节点加速。  改进后的Find操作如下:

 



关于Union-Find data structure 的实现



实现算法代码如下:






例如, 具体的, 如下:














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值