您的位置:首页 > 其它

并查集---一点小的感悟

2011-06-07 15:51 302 查看
最近在做ACM题,遇到了一个叫做并查集的东西,于是从网上找了一些资料,顺便自己总结了一些,希望对大家和自己都有用~~
(一)什么叫做并查集
英文:Disjoint
Set,即“不相交集合”
将编号分别为1…N的N个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。
常见两种操作:

1、n合并两个集合

2、n查找某元素属于哪个集合
例如,并查集一般用数组来实现,用数组的下标序号作为其元素的代号,其中的每个元素都属于一个集合,初始条件下每个元素所属的集合中只有其一个元素,例如对于元素i来说,其所属的集合为Set[i],在实际应用中要将各个集合进行合并,用编号最小的元素的下标作为整个集合的代号。
n 用编号最小的元素标记所在集合;
n 定义一个数组 set[1..n]
,其中set[i] 表示元素i 所在的集合;



例如上图中,目前元素1、3、7都属于集合1,也就是set[1]=set[3]=set[7]=1;同理,元素2、5、9、10都属于集合2,等等。用数学语言描述,不相交的集合共有四个: {1,3,7}, {4}, {2,5,9,10}, {6,8}
上面的算法的实现过程如下:



其中,左图表示查找相应元素所在的集合,右图表示将两个集合相合并,当然前提条件是参数a,b分别表示的是集合。其复杂度不难计算出来:右图中的算法包括一个循环,此循环的复杂度为O(N),当元素的个数很少是还能接受,但是当元素的个数很多时,其运算速度很难让人接受。
为了改进合并算法,将元素用树的形式表示出来:
n 每个集合用一棵“有根树”表示
n 定义数组 set[1..n]
n
set[i] = i , 则i表示本集合,并是集合对应树的根
n
set[i] = j, j<>i, 则 j 是 i 的父节点.



下面是其算法



从树中的每个节点开始顺着其父节点向上查找,直到找到其相应的根节点。


其复杂度算法也是容易算出的,先说查找算法:当树是一个左偏树或者右偏树时,其复杂度为O(N),但是当树为一个普通的树时,其复杂度为从此节点到其根节点的层数的复杂度,其复杂度为 。合并的算法的复杂度为O(1);
由于合并的时候是随机合并的,因此容易形成左偏树或者右偏树,这样不利于降低查找算法的复杂度,为了节省算法开销,作如下的改进。
n 方法:将深度小的树合并到深度大的树
n 实现:假设两棵树的深度分别为h1和h2, 则合并后的树的高度h是:
n max(h1,h2), if h1<>h2.
n

h1+1, if h1=h2.
n 效果:任意顺序的合并操作以后,包含k个节点的树的最大高度不超过
其算法如下所示:



为了进一步优化算法,可以进行路径压缩:
n 思想:每次查找的时候,如果路径较长,则修改信息,以便下次查找的时候速度更快
n 步骤:
n 第一步,找到根结点
n 第二步,修改查找路径上的所有节点,将它们都指向根结点
算法如下:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: