并查集是一种树型的数据结构 ,并查集可以高效地进行如下操作:
1. 查询元素p和元素q是否属于同一组
2. 合并元素p和元素q所在的组
1.简单实现
定义数组int[] UF, 数组下标表示值value,而数组存储的值UF[i] 表示所在的分组。
2.优化实现
为了提升算法的性能,我们仍然定义数组int[] UF, 数组下标表示值value,而数组存储的值UF[i] 表示该 i 结点的父结点所在索引。当UF[i] - i 时, i 为小组的根节点。
3.路径压缩
为了保证树的平衡性,提高效率。我们要保证每次合并,都能把小树合并到大树上,就能够压缩合并后新树的路径。定义一个新数组来记录存储每个根结点对应的树中元素的个数。
4.代码实现
public class UF_Tree_Weighted {
//记录结点元素和该元素所在分组的标识
private int[] eleAndGroup;
//记录并查集中数据的分组个数
private int count;
//用来存储每一个根结点对应的树中保存的结点的个数
private int[] sz;
//初始化并查集
public UF_Tree_Weighted(int N){
//初始化分组的数量,默认情况下,有N个分组
this.count = N;
this.eleAndGroup = new int[N];
//初始化eleAndGroup
for (int i = 0; i < eleAndGroup.length; i++) {
eleAndGroup[i] = i;
}
this.sz = new int[N];
//默认情况下,sz中每个索引处的值都是1
for (int i = 0; i < sz.length; i++) {
sz[i] = 1;
}
}
//获取当前并查集中的数据有多少个分组
public int count(){
return count;
}
//判断并查集中元素p和元素q是否在同一分组中
public boolean connected(int p,int q){
return find(p) == find(q);
}
//元素p所在分组的标识符
public int find(int p){
while(true){
if (p == eleAndGroup[p]){return p;}
p = eleAndGroup[p];
}
}
//分组合并
public void union(int p,int q){
//找到p和q所在组对应的树的根结点
int pRoot = find(p);
int qRoot = find(q);
if (pRoot==qRoot){ return; }
//把较小的树合并到较大的树中
if (sz[pRoot]<sz[qRoot]){
eleAndGroup[pRoot] = qRoot;
sz[qRoot]+=sz[pRoot];
}else{
eleAndGroup[qRoot] = pRoot;
sz[pRoot]+= sz[qRoot];
}
this.count--; //组的数量-1
}
}