定义:
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。
主要构成:
并查集主要由一个整型数组pre[ ]和两个函数find( )、join( )构成。
数组 pre[ ] 记录了每个点的前驱节点是谁,函数 find(x) 用于查找指定节点 x 属于哪个集合,函数 join(x,y) 用于合并两个节点 x 和 y 。
作用:
并查集的主要作用是求连通分支数(如果一个图中所有点都存在可达关系(直接或间接相连),则此图的连通分支数为1;如果此图有两大子图各自全部可达,则此图的连通分支数为2……)
并查集的初始化
将所有元素的前驱都设为他自己。
find()函数
我们需要定义一个数组:int fa[1000]; (数组长度依题意而定)。这个数组记录了每个元素的前驱结点是谁。比如说fa[16]=6就表示16号元素的前驱结点是6号。如果一个元素的前驱结点就是他自己,那说明他就是代表元了,查找到此结束。也有一个元素自及组成一个集合的,那么这个集合的代表元就是自己。
int find(int x) { //并查集(路径压缩)
if(x != fa[x]) { //当x不等于它的爸爸时(当它是祖先时,它没有爸爸)
fa[x] = find(fa[x]);//继续找他的爸爸的爸爸
}
return fa[x];//返回祖先
}//查找
join函数
join函数的作用是将两个集合合并,合并两个集合的关键是找到两个集合的代表元,将其中一个作为另一个的前驱结点即可。
void join(int x,int y)
{
int fx=find(x), fy=find(y);
if(fx != fy)
fa[fx]=fy; //fy做fx的前驱结点
}
路径压缩算法:加权标记法
主要思路:
加权标记法需要将树中所有节点都增设一个权值,用以表示该节点所在树中的高度(比如用rank[x]=3表示 x 节点所在树的高度为3)。这样一来,在合并操作的时候就能通过这个权值的大小来决定谁当谁的前驱结点。
在实际写代码时,为了使代码尽可能简洁,我们可以将第1点单独作为一个逻辑选择,然后将2、3点作为另一个选择(反正第2点任意指定上级嘛),所以具体的代码如下:
void union(int x,int y)
{
x=find(x); //寻找 x的代表元
y=find(y); //寻找 y的代表元
if(x==y) return ; //如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并,直接返回;否则,执行下面的逻辑
if(rank[x]>rank[y]) pre[y]=x; //如果 x的高度大于 y,则令 y的上级为 x
else //否则
{
if(rank[x]==rank[y]) rank[y]++; //如果 x的高度和 y的高度相同,则令 y的高度加1
fa[x]=y; //让 x的上级为 y
}
}