码迷,mamicode.com
首页 > 其他好文 > 详细

并查集

时间:2015-02-17 21:03:07      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:

并查集是一种数据结构,一般用来解决连通性或者动态连通性的问题。

动态连通性:

即一个图有n个结点,不断加入边,问此时任意两个结点的连通性。

建模思路:

对于连通的结点它们属于一个组,不连通的结点就属于不同的组。对于每一条边的输入,

判断两个结点是否连通,如果不连通则将两个结点所属的两个组连成一个组。对于每一个组,设置一个组标志。

初始时,任意两个结点不连通,组标志就是自己。

for(i=0; i<n; ++i)
    father[i] = i;

组的体现形式:

连通的结点属于一个组,那么组内是怎么体现的呢?

是用树来实现的

技术分享

左边一个组,组的标志是a,右边一个组,组的标志是e

然后father[b] = a,father[c] = a, father[d] = d;

如果每个结点的终极祖先相同,那么就是一个组。
查找结点属于哪一个组的算法find

1 int find(int x)
2 {
3     if(x==parent[x]) return x;//如果自己的父亲是自己,那么就是这个组的标志
4     return find(parent[x]);//否则,看父亲的父亲是不是组的标志
5 }

如果输入一条边u-->v。如果u和v不属于一个组,那么就把两个组变成一个组

1 int Union(int u, int v)
2 {
3     int ru = find(u);
4     int rv = find(v);
5     if(ru != rv)
6     {
7         parent[ru] = rv;
8     }
9 }


但是会发生一个问题,那就是极端下,树的高度可能会很极端

技术分享

所以要进行路径压缩,即在find()函数返回的过程中,修改father数组

 

1 int find(int x)
2 {
3     if(x==parent[x]) return x;//如果自己的父亲是自己,那么就是这个组的标志
4     return parent[x] = find(parent[x]);//返回的过程中修改father数组,路径压缩
5 }

 

可是仍然存在问题,如果Union很多次,才find一次,那么极端情况下,情况仍然不理想,所以就存在按秩合并

低的树指向高的树,不会增加书高,即按秩合并

 1 int Union(int u, int v)
 2 {
 3     int ru = find(u);
 4     int rv = find(v);
 5     if(ru != rv)
 6     {
 7         if(rank[ru] <= rank[rv])
 8         {
 9             parent[ru] = rv;
10             if(rank[ru]==rank[rv])
11                 rank[rv]++;
12         }
13         else
14             parent[rv] = ru;
15     }
16 }

 

并查集

标签:

原文地址:http://www.cnblogs.com/justPassBy/p/4295439.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!