- 作用:求连通分支数
- 构成:
- 整形数组 pre[]:记录每个节点的前向导点
- find() 函数:查找
- join() 函数:合并
find() 函数:对于每个点查找其上级
int find(int x){while(pre[x] != x){ //上级为自己就是最高级了x = pre[x];}return x;}
join() 函数:合并两个连通分支
void join(int x,int y){int fx = find(x), fy = find(y);if(fx != fy){pre[fx] = fy;}}
路径压缩法:将 x 到根节点路径上的所有点的 pre(上级) 都设为根节点
int find_pre(int x){if(pre[x] == x){return x;}return pre[x] = find_pre(pre[x]);}
加权标记法:给每个节点标记树的深度,合并后不产生树退化(左右子树的深度差尽可能小),维护一个 rank[x] 数组,用以表达树 x 的深度,合并时,若 rank[x] < rank[y] ,令 pre[x] = y,否则相反
void union(int i,int j){i = find_pre(i);j = find_pre(j);if(i == j){return;}if(rank[i] > rank[j]){pre[j] = i;}else{if(rank[i] == rank[j]){rank[j]++;}pre[i] = j;}}
模板
class UnionFind{int[] parent; // parent[i]表示i这个元素指向的父亲节点int[] size; //size[i]表示以i为根节点的集合中元素个数int n; //节点的个数,初始化每一个节点都是一个单独的连通分量int setCount; //连通分量的数目public UnionFind(int n){this.size=new int[n];this.parent=new int[n];this.n=n;this.setCount=n;Arrays.fill(size,1);for(int i=0;i<n;i++){parent[i]=i;}}public int find(int x){return parent[x]==x?x:find(parent[x]);}public boolean unit(int x,int y){x=find(x);y=find(y);if(x==y){return false;}if(size[x]<size[y]){int tem=x;x=y;y=tem;}parent[y]=x;size[x]+=size[y];--setCount;return true;}public boolean connected(int x, int y) {x = find(x);y = find(y);return x == y;}}
