并查集

不相交​​集合​​(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

      并查集是一种树形结构,又叫“不相交集合”,保持了一组不相交的动态集合,每个集合通过一个代表来识别,代表即集合中的某个成员,通常选择根做这个代表。

并查集的优化:

Union(x, y)时按秩合并:

合并时,如果两个集合的秩相同,任选一个根做为父节点,并增加其秩。

秩不同时,让较小秩的集合指向较大秩的集合,这时秩的大小不变。

秩和集合的数目是不一样的,秩表示节点高度的一个商界;集合的数目表示集合中节点的总数。

Find_Set(x)路径压缩:

在Find_Set(x)中,是查找路径上的每个节点都直接指向根节点,这样下次再找根节点的时间复杂度会变成o(1);

 

1、Find_Set(x)时 路径压缩
寻找祖先时我们一般采用递归查找,但是当元素很多亦或是整棵树变为一条链时,每次Find_Set(x)都是O(n)的复杂度,有没有办法减小这个复杂度呢?
答案是肯定的,这就是路径压缩,即当我们经过"递推"找到祖先节点后,"回溯"的时候顺便将它的子孙节点都直接指向祖先,这样以后再次Find_Set(x)时复杂度就变成O(1)了,如下图所示;可见,路径压缩方便了以后的查找。

2、Union(x,y)时 按秩合并

即合并的时候将元素少的集合合并到元素多的集合中,这样合并之后树的高度会相对较小。


并查集,合并 以及优化_路径压缩

 

 

重量权衡合并规则 
1、每次合并前都需要进行两次查找,查找所需要的时间由树的高度决定,合并所需的时间为O(1)容易看出,在最坏情况下合并可能使n个结点的树退化成一条链
2、为了防止树退化为单链,应该让每个结点到其相应根结点的距离尽可能小,可以做如下两种改进
  2.1 在做“合并”操作之前先判别子集中所含成员的数目,然后令含成员少的子集的树根指向含成员多的子集的根,称作“重量权衡合并规则”(weightedunion rule)。把小树合并到大树中去,可以把树的整体深度限制在O(logn),每次Find操作只需要O(logn)时间
  2.2 在执行Union时总是将小树并到大树上,而且在执行Find时实行路径压缩,以提高效率

 

 

并操作

将包含x,y的动态集合合并为一个新的集合。合并两个集合的关键是找到两个集合的根节点,如果两个根节点相同则不用合并;如果不同,则需要合并。 
这里对并操作有两种优化:根节点存树高的相反数或者根节点存集合的个数的相反数,这两种方法统称按秩归并。通常选用第二种方法。