Union-find算法(algs4)

1.    动态连通性问题

目标:编写一个程序过滤掉序列中无意义的整数对(两个整数均来自同一个等价类中)。

问题描述:当程序从输入中读取了整数对p、q时,如果已知的所有整数对都不能说明p和q是相连的,那么则将这一对整数写入到输出中。如果已知的数据可以说明p和q是相连的,那么程序应该忽略p、q这对整数并继续处理输入中的下一对整数。

应用:网络、变量名等价性、数学集合

网络方面的术语:对象称为触点,整数对成为连接,等价类称为连通分量或是简称分量。

 

2.    API

 

                                Union-find算法的API

 Pubic class UF

 private int[] id;                                         分量id

 private int count;                                      分量数量

 public UF(int N)                                       以整数标识(0—N-1)初始化N个触点

 public int count()                                      连通分量的数量

 public boolean connected(int p,int q)          如果p和q存在于同一个分量中则返回true             

 public int find(int p)                                   p(0—N-1)所在分量的标志符

 public void union(int p,int q)                       在p和q之间添加一条连接

 public static void main(String[] args)

 

main()方法:

从输入读取N值以及一系列整数对,并对每一对整数调用connected()方法;如果某一对整数中的两个触点已经连通,程序会继续处理下一对数据;如果不连通,程序会调用union()方法并打印这对整数。

 

用一个以触点为索引的数组id[]作为基本数据结构来表示所有数据分量

 

3.quick-find算法

 

package _1_3linkedList;

import java.util.Scanner;

/*算法1.5 union-find 的实现
*/
public class UF
{
	private int[] id;     /*分量id(以触点为索引)*/
	private int count;      /*分量数量*/
	public UF(int N)
	{                       /*初始化分量id数组*/
		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);
	}
	/******************quick-find算法****************************/
	/*
	 * 使用分量中某个触点的名称作为分量的标志符
	 * 同一个连通分量中的所有触点在id[]中的值必须全部相同
	 * 如果最后得到一个连通分量,那么这个算法运行时间是平方级别的
	 * */
	public int find(int p)
	{
		return id[p];
	}
	public void union(int p,int q)     /*将p和q归并到相同的数组*/
	{
		int pId=find(p);
		int qId=find(q);
		if(pId==qId)
			return;
		for(int i=0;i<id.length;i++)/*遍历数组,和p连同的分量要连接到q上去*/
			if(id[i]==pId)
				id[i]=qId;
		count--;
	}
	
	public static void main(String[] args)
	{
		int N;
		int p = 0;
		int q;
		Scanner sc=new Scanner(System.in);
		
		N=sc.nextInt();             /*读取触点数量*/
		UF uf=new UF(N);            /*初始化N个分量*/
		while(true)
		{
			p=sc.nextInt();
			if(p==-1)
				break;
			q=sc.nextInt();             /*读取整数对*/
			if(uf.connected(p, q))     /*如果已连同则忽略*/
				continue;
			System.out.println(p+" "+q);  /*否则打印并归并分量*/
			uf.union(p, q);
		}
		System.out.println(uf.count()+"components");
	}
}

                                                                      


4.quick-union算法


	/******************quick-union算法****************************/
	/*
	 * 每个触点所对应的id[]元素都是同一个分量中的另一个触点的名称(也可能是他自己的:根触点)
	 * 当且仅当分别由两个触点开始的这个过程到达了同一个根触点时它们存在于同一个连通分量之中
	 * 如果最后得到一个连通分量,那么这个算法最佳情况下运行时间是线性级别最坏情况下是平方级别
	 * */
	public int find(int p)
	{
		while(p!=id[p])
			p=id[p];
		return p;
	}
	public void union(int p,int q)
	{
		int pRoot=find(p);
		int qRoot=find(q);
		if(pRoot==qRoot)
			return;
		id[pRoot]=qRoot;
		count--;
	}


                                      

                                                                                       id[pRoot]=qRoot


                                     

 

5.加权quick-union算法

 

package _1_3linkedList;

import java.util.Scanner;

/*加权quick-union算法
 * 添加一个数组和一些代码来记录树中的节点数
 * 此算法能保证对数级别的性能
*/
public class WeightedQuickUnionUF
{
	private int[] id;     /*分量id(以触点为索引)*/
	private int count;      /*分量数量*/
/**/private int[] sz;     /*(由触点索引的)各个根节点所对应的分量的大小*/
	public WeightedQuickUnionUF(int N)
	{                       /*初始化分量id数组*/
		count=N;
		id=new int[N];  /*!!!*/
/**/	sz=new int[N];
		for(int i=0;i<N;i++)
			{
				id[i]=i;
/**/			sz[i]=1;
			}
		
	}
	public int count()
	{
		return count;
	}
	public boolean connected(int p,int q)
	{
		return find(p)==find(q);
	}
	public int find(int p)
	{
		while(p!=id[p])           /*找到根节点*/
			p=id[p];
		return p;
	}
	public void union(int p,int q)
	{
		int pRoot=find(p);
		int qRoot=find(q);
		if(pRoot==qRoot)
			return;
/**/		if(sz[pRoot]>sz[qRoot])/*将小树的根节点连接到大树的根节点*/
		{
			id[qRoot]=pRoot;
/**/		sz[qRoot]+=sz[pRoot];
		}
		else
		{
			id[pRoot]=qRoot;
/**/		sz[pRoot]+=sz[qRoot];
		}
		count--;
	}
	public static void main(String[] args)
	{
		int N;
		int p = 0;
		int q;
		Scanner sc=new Scanner(System.in);
		
		N=sc.nextInt();             /*读取触点数量*/
		WeightedQuickUnionUF wquf=new WeightedQuickUnionUF(N);            /*初始化N个分量*/
		while(true)
		{
			p=sc.nextInt();
			if(p==-1)
				break;
			q=sc.nextInt();             /*读取整数对*/
			if(wquf.connected(p, q))     /*如果已连同则忽略*/
				continue;
			System.out.println(p+" "+q);  /*否则打印并归并分量*/
			wquf.union(p, q);
		}
		System.out.println(wquf.count()+"components");
	}

}


6.比较



                                                     


                       

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值