动态连通性问题。要点在find和union两个函数,用四种方法实现(愈趋优化)。
这些方法主要在find和union函数上不同。
A. quick-find算法
package com.Page1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class UF {
private int[] id;//分量id,注意是以触点值作为索引
private int count;//分量数
UF(int N)//初始化N个触点
{
id=new int[N];
count=N;
for(int i=0;i<N;i++)
{
id[i]=i;//初始化每个触点的id为自身
}
}
public int count()
{
return count;
}
public boolean connected(int p,int q)
{
return find(p)==find(q);
}
public int find(int p) //所属组的id号直接可得
{
return id[p];
}
public void union(int p,int q)
{
int x=id[p];
int y=id[q];
if(x==y) return;
for(int i=0;i<id.length;i++) //修改p组的所有id号为q组的id号
{
if(id[i]==x)
id[i]=y;
}
count--;
}
public static void main(String[] args) throws IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int N;
System.out.println("please input N: ");
N = Integer.parseInt(reader.readLine()); //将输入流转为int型
UF uf=new UF(N);
int p,q;
String input;
System.out.println("please input pairs: ");
input = reader.readLine();
String x[]=input.split(" ");
p=Integer.parseInt(x[0]);
q=Integer.parseInt(x[1]);
while(p!=-1) //假设当输入数据的p为-1时代表输入完成
{
if(!uf.connected(p,q))//若该组之前未连接
{
uf.union(p, q);
}
input = reader.readLine(); //继续输入下一组数据
x=input.split(" ");
p=Integer.parseInt(x[0]);
q=Integer.parseInt(x[1]);
}
System.out.println("the number of count is: "+uf.count());
}
}
B.quick-union算法
public int find(int p)
{
while(id[p]!=p) //一直找,直到找到p所属组的源头(即每组源头就一个,但该组中的元素的id不同)
p=id[p];
return p;
}
public void union(int p,int q)
{
int x=find(p);
int y=find(q);
if(x==y) return;
id[x]=y;//将某组的源头的id值改成另一组的源头id
count--;
}
C.加权quick-union算法
private int[] id;//分量id,注意是以触点值作为索引
private int count;//分量数
private int[] sz;//各个根节点对应的分量大小
UF(int N)//初始化N个触点
{
id=new int[N];
sz=new int[N];
count=N;
for(int i=0;i<N;i++)
{
id[i]=i;//初始化每个触点的id为自身
sz[i]=1;//分量大小初始化为1
}
}
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=id[p];
return p;
}
public void union(int p,int q)
{
int x=find(p);
int y=find(q);
if(x==y) return;
//比较x和y的分量包含大小,将小的一个分量加到大分量上
if(sz[x]<sz[y])
{
id[x]=y;sz[y]+=sz[x];
}
else
{ id[y]=x;sz[x]+=sz[y];}
count--;
}
D.路径压缩的加权quick-union算法(最优)
(其余代码与算法C相同)
public int find(int p)
{
int parent=p;
int p1;
while(id[parent]!=parent) //一直找,直到找到p所属组的源头(即每组源头就一个,但该组中的元素的id不同)
parent=id[parent];
//从p开始再一次循环,将路上遇到的节点的父节点都设为刚才找到的根节点
while(p!=id[p])
{
p1=id[p];
id[p]=parent;
p=p1;
}
return parent;
}