在判断一个图是否联通的时候用union-find与quick-find算法来进行判断:
quick-find中的算法为:定义一个数组来存根节点的值,只要属于此类,就将在此类节点中的值都设为根节点,将其归为一类,当两类互相向连接的时候,则需要将其中的一个类的所有节点的的值都改为另外一类中的根节点。
具体实现:
private int[] id;
private int count;
public quick_find(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 connectend(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]==pID)id[i]=qID;//每个节点对应他的根节点
count--;
}
利用主函数来调用函数内的union中的连接;
算法quick-union中的算法实现:
思想:在quick-find中每次调用union中都会遍历一遍数组,算法复杂度高。则quick-union则将每一个节点记住他的根节点,然后不断记录根节点。当两个类互相连接的时候,则将这个类中的一个节点的下一个节点记录为这个类中的节点;
代码实现:
package Algorithm;
import java.util.Scanner;
public class union_find {
/*
* 实现union_find算法:
* 体现:找寻两个点之间是否是联通
* 思想:定义一个数组进行存储每个点的下一个点的值
* 如:A[i]=j;为此点为i,,其下一个节点为j来进行联通表示
* 首先要进行初始值,将其每一个值都定义为他们原来的值
*
*
* */
private int[] id;
private int count;
public union_find(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) {
while(id[p]!=p)p=id[p];//下一个节点
return p;//为最后的根节点
}
public void union(int p,int q) {//进行判断是否进行创新新节点
int i=find(p);//找寻其节点
int j = find(q);
if(i==j) return ;
id[q]=p;
count--;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner= new Scanner(System.in);
int N = scanner.nextInt();
union_find uf = new union_find(N);
while(!scanner.hasNext()) {
int p =scanner.nextInt();
int q = scanner.nextInt();
if(uf.connected(p, q))continue;
uf.union(p, q);
System.out.println(p+" "+q);
}
System.out.println(uf.count+" components");
}
}
主函数有点错!!需要输入几组数据的时候请具体分析!
加权quick-uion在前两个基础上,由于不可以判断哪一个类的节点多,则耗时会很大,则我们可以定义一个函数来存储每一个类中的节点数目,则可以将小类归纳到大类中去,避免大类归纳到小类,具体代码:
public void union(int p,int q) {//进行判断是否进行创新新节点
int i=find(p);//找寻其节点
int j = find(q);
if(i==j) return ;
if(num[i]<num[j]) {//判断谁的子节点多,多的话则将其设为大树
id[i]=j;//头节点指向j的头几点
num[j]+=num[i];
}
else {
id[j]=i;
num[i]+=num[j];
}
count--;
}