并查集原理及其实现

并查集,听起来可能有点陌生的数据结构,他和树的思想类似,但是肯定也有所不同。

今天我们就来简单介绍一下并查集的思想,和一步一步的优化。

首先简单的并查集是用数组实现的,如果要存储一些比较特殊的数据可以用类或者结构体来实现。

简单介绍,int 数组的实现,数组的下标表示这个数组的数,下标对应的数表示,这个数的父亲。

并查集的基本方法就是查找最顶层父节点,和两个数是否连接就是查找两个数的顶层节点是否相同。把两个数连接起来。

最简单的实现上代码:

public Integer find(int p) {
		if(p<0||p>=arr.length) {
			return  null;
		}
		return arr[p];
	}
	
	public boolean isConnect(int p,int q) {
		return  find(p)==find(q);
	}
	
	
	public void connectElement(int p,int q) {
		if(!(find(p)==find(q))) {
			for(int i=0;i<arr.length;i++) {
				if(arr[i]==find(q)) {
					arr[i]=find(p);
				}
			}
		}
	}

但是这种效率比较低 尤其是在两个数连接的时候,效率尤其底下

我们只需要把要查找的两个数的顶层节点连接起来就行啦,不需要循环赋值代码如下

这样还能再次优化就是,在两个数的连接的时候,我们应该把当前级数最少的合并到多的那一列,就可以减少级数的增多。就需要声明一个级数数组,然后在connecElement的时候需要维护rank数组。

最后的优化就是,把所有的级数压缩到只有一层,父节点和子节点,这样保证级数最少,查找最快,连接最快,代码优化如下。

最后终极优化代码

package algorithm.unionfind;
/** 
* @author 作者 liwei: 
* @version 创建时间:2018年12月24日 下午1:16:12 
* 类说明 
*/
public class UnionFind2 {
	private int [] arr;
	private int [] sz;
	private int [] rank;
	private int [] parent;
	
	
	public UnionFind2() {
		super();
		this.arr = new int [5];
		this.rank = new int [20];
		this.parent = new int [20];
	}
	public void  init() {
		for(int i=0;i<arr.length;i++) {
			arr[i]=i;
			rank[i]=1;
			parent[i]=i;
		}
	}
	public Integer find(int p) {
		if(p<0||p>=arr.length) {
			return  null;
		}
		
//		while(p!=arr[p]) {
//			arr[p]=arr[arr[p]];
//			p=arr[p];
//		}
		if(p==arr[p])
			return p;
		int t=find(arr[p]);
		arr[p]=t;
		return arr[p];
	}
	
	public boolean isConnect(int p ,int q) {
		return find(p)==find(q);
	}
	
	public void connectElementDev(int p,int q) {
		Integer pRoot = find(p);
		Integer qRoot = find(q);
		if(pRoot==qRoot) return ;
		if(rank[pRoot]>rank[qRoot]) {
			arr[qRoot]=pRoot;
		}
		else if(rank[pRoot]<rank[qRoot]) {
			arr[pRoot]=qRoot;
		}
		else {
			arr[pRoot]=qRoot;
			rank[qRoot] +=1;
		}
	}
	public static void main(String[] args) {
		UnionFind2 uf2 = new UnionFind2();
		uf2.init();
		int arr[]=uf2.arr;
		for(int i =0;i<arr.length-1;i++) {
			arr[i]=i+1;
		}
		arr[arr.length-1]=arr.length-1;
		uf2.find(0);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值