并查集类似静态链表,使用数组实现,元素的值就是指针指向,即父结点。
每个集合中选出一个代表,这个代表就是这棵树中的根。
按秩合并
每个集合中选出一个代表,这个代表就是这棵树中的根。
每个元素指向其父亲,根节点的值指向自己。
并查集树的表示
并查集的基本操作:
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]++; } }