9.6 并查集
9.6.1 并查集的定义
并查集是一种维护集合的数据结构,他的名字中“并”、“查”、“集”分别取自Union(合并)、Find(查找)、Set(集合)。也就是说,并查集支持下面两个操作:
- 合并:合并两个集合
- 查找:判断两个元素是否在一个集合。
那么并查集用什么实现呢?其实就是用一个数组:
int father[N] ;
其中father[i]表示元素i的父亲结点,而父亲结点本身也是这个集合内的元素。如果fatjer[i]==i,则说明元素i是该集合的根结点。但对同一个集合来说只存在一个根节点,且将其作为所属集合的标识
例如
father[1] = 1 ; //1的父亲结点时自己,也就是说1是根结点
father[2] = 1 ; //2的父亲结点时1
9.6.2 并查集的基本操作
总体来说,并查集的使用需要先初始化fatner数组,然后再根据需要进行查找或合并的操作。
1. 初始化
一开始,每个元素都是独立的一个集合,因此令所有father[i] = i
for( int i = 1 ; i<= N ; i++){
father[i] = i ;
}
2. 查找
由于规定同一个集合只存在一个根结点,因此查找操作就是对给定的结点寻找其根结点的过程。即反复寻找父亲结点,直到找到根结点。
递推方式
int findFather( int x ){
while( x != father[x] ){ //不是根结点
x = father[x] ;//获得自己的父亲节点
}
return x ;
}
递归方式
int findFather( int x ){
if( x == father[x] ){
return x ;
}
else{
findFaher( father[x] ) ;
}
}
3. 合并
合并是指把两个集合合并成一个集合,题目中一般给出两个元素,要求把这两个元素所在的集合合并。具体实现上一般实现判断两个元素是否数与同一个集合,只有当两个元素属于不同集合时才合并,而合并过程一般是把其中一个集合的根结点的父亲指向另一个集合的根结点。
void Union( int a , int b ){
int faA = findFather(a) ;
int faB = findFather(b) ;
if( faA != faB ){
father[faA] = faB ; //合并
}
}
最后说明并查集的一个性质。在合并的过程中,只对两个不同的集合进行合并,如果两个元素在相同的集合中,那么就不会对它们进行操作。这就保证了在同一个集合中一定不会产生环,即并查集产生的每一个集合都是一棵树。