并查集 Union Find

本文深入探讨并查集数据结构的原理与应用,详细解释如何通过并查集优化数据连接判断与合并操作,降低时间复杂度。文章介绍并查集的底层实现,包括子节点指向父节点的独特结构,以及在查找和合并过程中如何通过路径压缩和树的等级优化来减少树的深度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

并查集:在进行判断两个数据之间是不是有连接的操作中。如果我们单独用数组进行数据的存储,把有连接的数据的ID设置成相同的数字,那么这种数据结构进行查找操作的时候,时间复杂度是O(1),但是进行合并的时候,所进行的时间复杂度是O(n)。对于数据量较大的情况,O(n)将会是个非常慢的操作。所以这个时候需要并查集这种数据结构。这种数据结构更像是森林,每棵树上的数据是有连接的,不同树之间的数据是没有连接的。如果想合并,只需要将两棵树的根节点进行合并。所以这就导致了并查集的树和别的树不一样。

  并查集的树的结构是子节点指向父节点,父节点的值指向自己。底层实现仍然是数组,数组的index是所要查找的节点,数组的值代表的是这个节点上一层的节点。想要判断两个节点是否有连接,只需要判断两个节点的根节点是不是同一个值。这样达到的时间复杂度在查找和合并上都是h(h代表的是树的深度)。所以肯定是树的深度越低越好,这就要进行优化,可以定义一个数组记录每个根节点底下树的深度,当进行合并的时候,把根节点树的深度低的连接向根节点树深度高的节点。除了这个优化之外,还可以进行路径的压缩,就是当进行查询根节点的过程中,把要相应的节点跳过父节点,而指向父亲的父亲节点,然后一直循环到根节点。这样可以有效降低树的深度。所以那个记录的也不能成为树的深度,可以理解成树的等级,深度越高等级越高,每次都把高等级的树连接到低等级的树的根节点上。

//要实现的接口
public interface UF {
	public int getSize();
	public void union(int p,int q);
	public boolean isConnection(int p,int q);

}
//实现接口的类
public class QuickUnion implements UF{
	//记录每个数值所属的集合
	private int[] ID;
	//记录每个根节点下的子节点的个数
	private int[] rank;
	public QuickUnion(int size) {
		ID = new int[size];
		rank = new int[size];
		for(int i = 0;i<size;i++) {
			ID[i] = i;
			rank[i] = 1;
		}
	}
	
	@Override
	public int getSize() {
		return ID.length;
	}
	//找到节点的父亲节点并在查找的过程中进行路径的压缩
	public int find(int p) {
		while(p != ID[p]) {
			ID[p] = ID[ID[p]];
			p = ID[p];
		}
		return p;
	}
	
	//判断两个节点是否有链接
	@Override
	public boolean isConnection(int p, int q) {
		return find(p) == find(q);
	}
	
	//合并两个节点
	@Override
	public void union(int p,int q) {
		int pID = find(p);
		int qID = find(q);
		if(pID == qID) {
			return ;
		}
		if(rank[pID]<rank[qID]) {
			ID[pID] = qID;
		}
		else if(rank[pID]>rank[qID]){
			ID[qID] = pID;
		}
		else {
			ID[qID] = pID;
			rank[qID] +=1;
		}
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值