quick-find算法
public class UF {
private int[] id; //分量id
private int count; //分量数量
public UF(int N){
count = N;
id = new int[N];
for(int i = 0;i < N;i++){
id[i] = i;
}
}
public int count(){
return count;
}
public boolean connected(int p,int q){
return find(p) == find(q);
}
public int find(int p){
return id[p];
}
public void union(int p,int q){
int pId = find(p);
int qId = find(q);
if(pId == qId){
return;
}
for(int i = 0;i < id.length;i++){
if(id[i] == qId){
id[i] = qId;
}
}
count--;
}
}
find()操作的速度显然是很快的,因为它只需要访问id[]数组一次。但quick-find算法一般无法处理大型问题,因为对于每一组输入union()都需要扫描整个id[]数组。
quick-union算法
public class QuickUnionUF {
private int[] id;
public QuickUnionUF(int N){
id = new int[N];
for(int i = 0;i < N;i++){
id[i] = i;
}
}
private int root(int i){
while (id[i] != i){
i = id[i];
}
return i;
}
public boolean connected(int p,int q){
return root(p) == root(q);
}
public void union(int p,int q){
int i =root(p);
int j = root(q);
id[i] = j;
}
}
树的深度会影响这个算法的时间复杂度。
加权quick-union算法
public class WeightedQuickUnionUF {
private int[] id; //分量id
private int[] sz; //各个根节点所对应的分量的大小
private int count; //分量数量
public WeightedQuickUnionUF(int N){
count = N;
id = new int[N];
for(int i = 0;i < N;i++){
id[i] = i;
}
for(int i = 0;i < N;i++){
id[i] = 1;
}
}
public int count(){
return count;
}
public boolean connected(int p,int q){
return find(p) == find(q);
}
private int find(int i){
while (id[i] != i){
id[i] = id[id[i]]; //路径压缩,使树变得扁平化。
i = id[i];
}
return i;
}
public void union(int p,int q){
int pId = find(p);
int qId = find(q);
if(pId == qId){
return;
}
//关键在于这个部分,每次判断两个树的大小,防止树的深度太大。
if(sz[pId] < sz[qId]){
id[pId] = qId;
sz[qId] += sz[pId];
}else{
id[qId] = pId;
sz[pId] += sz[qId];
}
count--;
}
}