1.5 union-find算法

动态连通性问题。要点在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;
	}




猜你喜欢

转载自blog.csdn.net/m0_37944102/article/details/81063134
今日推荐