并查集类似静态链表,使用数组实现,元素的值就是指针指向,即父结点。
每个集合中选出一个代表,这个代表就是这棵树中的根。
按秩合并
每个集合中选出一个代表,这个代表就是这棵树中的根。
每个元素指向其父亲,根节点的值指向自己。
并查集树的表示
并查集的基本操作:
1.void makeSet(int s):建立一个并查集,其中包含s个单元素集合
2.int find(int x):其中x是指要查找的元素的index,结果返回x所属集合的代表
这个代表告诉你它在哪个集合
注意在find的时候要进行路径压缩,否则查找效率就是树的高度
是log级别的而不是常数级了
3.void unionSet(int x,int y):合并两个元素所在的集合,就是将一个集合的代表指向
另一个集合的代表
合并有两种方案,两种方案都遵循弱肉强食的原则
非按秩合并:
const int MAXSIZE = 500;
int uset[MAXSIZE];
void makeSet(int size) {
for(int i = 0;i < size;i++) uset[i] = -1;
}
int find(int x) {<span style="white-space:pre"> </span>//递归find
if (uset[x] < 0) return x;
uset[x] = find(uset[x]);
return uset[x];
}
int find(int x) {
int p = x, t;
while (uset[p] >= 0) p = uset[p];
while (x != p) {
t = uset[x];
uset[x] = p;
x = t;
}
return x;
}
void unionSet(int x, int y) {
if ((x = find(x)) == (y = find(y))) return;
if (uset[x] < uset[y]) {
uset[x] += uset[y];
uset[y] = x;
} else {
uset[y] += uset[x];
uset[x] = y;
}
}
按秩合并
const int MAXSIZE = 500;
int uset[MAXSIZE];
int rank[MAXSIZE];
void makeSet(int size){
for(int i = 0;i<size;i++) uset[i] = i;
memset(rank,0,sizeof(rank));
}
int find(int x){
if(x!=uset[x]) uset[x] = find(uset[x]);
return uset[x];
}
void unionSet_1(int x,int y){
if((x=find(x))==(y=find(y)))
if(rank[x]>rank[y]) uset[y] = x;
else{
uset[x] = y;
if(rank[x]==rank[y]) rank[y]++;
}
}