并查集原理及实现

并查集能解决什么问题:

1.快速判断两个元素是否在同一个集合中。
2.合并两个元素所在集合,注意,输入的数据是两个元素,并不是两个集合,运算结果是将两个元素所在的集合合并。
3.并查集只适用于运算前已经将所有数据样本给它,不适用于动态添加数据,比如,运算到一半再用流来添加元素,并查集是不行的。

并查集结构及运算过程

1.并查集中,每个元素都有一个父元素,图中2和3号元素的父元素就是1号。
2.父元素指向本身的元素代表一个集合的终止。也就是说,2的父元素是1,1的父元素是它本身,那么,就说明元素2在集合1中。
3.初始化时,每一集合都只有自己本身一个元素,父节点全都指向自己本身。
4.判断两个元素是否在同一个集合中,就是两个元素各自依次遍历父元素,看看最终是否指向同一个终点元素,就是代表元素,代表一个集合。2和3向上的最终结果都是1,说明2和3在同一个集合1中。5向上是4,说明5在集合4中。
灵魂画手,不要介意表情😂
5.合并两个元素的集合,就是两个元素依次向上遍历,遍历到代表元素。然后判断两个集合哪个大?将小的集合链接在大集合的代表元素下面。比如,合并2和5所在的集合,2的所在集合是1,5所在集合是4,然后合并1和4,如下图。
在这里插入图片描述
6.并查集优化:如果链子太差的话,判断一个数是否在集合中,是不是需要向上遍历父节点很多次才能找到终点啊?这样效率就降低了。因此,并查集的优化,每次节点,当查询一次他在某个集合中时,就会把他以及他的所有父节点直接连接到代表节点上面,如下图,我们查询5所在集合时,就会把5以及父类中所有直接连接到代表节点上,5的子节点不动,如下图。
在这里插入图片描述

代码实现

public static class UnionFindSet{
	public HashMap<Node,Node> fatherMap;//key是孩子,value是父节点,父节点可重复
	public HashMap<Node,Integer> sizeMap;//某一个节点所在的集合共有多少节点,可以只保留代表节点。

	public UnionFindSet(List<Node> nodes){
		fatherMap=new HashMap<Node,Node>();
		sizeMap=new HashMap<Node,Integer>();
		makeSets(nodes);
	}

	private void makeSets(List<Node> nodes){
		for(Node node : nodes){
			fatherMap.put(node,node);//初始化时每一个集合都只有自己一个节点
			sizeMap.put(node,1);
		}
	}
	
	//找集合的头节点,并且将路径上的所有都直接连接在头节点上,递归实现
	//为什么要用递归实现?可以这样考虑,如果不用递归,我们需要保存路径中每个节点,然后等到找到代表节点时,将他们全部连接上。什么结构能保存运算中间的数据呢?递归可以,递归的本质是系统帮我们压栈,同时保存所有中间数据。
	private Node findHead(Node node){
		Node father = fatherMap.get(node);
		if(father!=node){
			father = findHead(father);
		}
		fatherMap.put(node,father);
		return father;
	}
	
	//判断是否在同一个集合
	public boolean isSame(Node a,Node b){
		return findHead(a)==findHead(b);
	}

	//合并集合
	public void union(Node a,Node b){
		if(a==null||b==null){
			return;
		}
		Node aHead=findHead(a);
		Node bHead=findHead(b);
		if(aHead!=bHead){
			int aSetSize=sizeMap.get(aHead);
			int bSetSize=sizeMap.get(bHead);
			if(aSetSize<=bSetSize){
				fatherMap.put(aHead,bHead);
				sizeMap.put(bHead,aSetSize+bSetSize);
			}else{
				fatherMap.put(bHead,aHead);
				sizeMap.put(aHead,aSetSize+bSetSize);
			}
		}
	}
}

并查集效率

并查集中放入的元素数量为N:
当查询次数+合并次数,达到O(N)及以上时,整个并查集中每一个查询以及合并的时间复杂度平均就为O(1)级别的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值