并查集

一、什么是并查集

并查集:其实也就是满足两种结构的一种数据结构
这两个结构分别为:①isSameSet结构,这个结构是用来查找两个元素是否属于一个集合
②还有一个是union结构,完成的就是把两个集合合并成一个大集合 
可以用Set和List来实现,但是需要对集合进行遍历,代价较高


二、并查集的逻辑实现

并查集的逻辑实现:对于每一个集合的每一个元素都有一个node,这个node含有自己的value和指向上级的指针
合并操作:刚开始进行合并操作的时候认为每一个单一的数据都是一个集合,这些集合的上级指针都指向本身,当进行合并操作的时候,每个数据较少的集合加到这个链表的后面;
合并过程发生了什么:先看每个集合的节点个数有多少,先把小的集合先对大集合进行isSameSet操作,若不是它的子集,则进行合并操作,把节点数少的集合直接挂在节点数多的集合最顶部节点的下面即可(若两个集合的节点数目是一样的,则这两个集合谁挂在谁下面是无所谓的)(以代表点来表示这个集合到底是什么)
查询两个数是否在一个集合里:其实就是查找这两个元素的代表点,若这两个元素的代表点一样则证明这两个元素在一个集合里,否则不在一个集合里

注:在进行查询的时候,当查到代表点的时候我们不先返回结果,先把你进行查询代表点的时候沿途的每一个点都指向代表点(并查集最重要的一个优化)
为什么要把沿途的所有节点进行打平:就是因为在下一次再查询这个元素对应的代表节点的时候其查询的时间会大大降低。

三、代码实现

public class UnionFind {

	public static class Data {
		// whatever you like
		//你需要的数据类型
	}

	public static class UnionFindSet {
		//fatherMap这个集合存储的是子节点的Data和指向父节点的Data(前面的是该节点的Data,后面的是指向的父节点的Data)
		//(key,value)--(A_Data,B_Data)-->表示的是A_Data的父节点是B_Data
		//这个fatherMap就是用来记录某个节点的父节点是谁
		public HashMap<Data, Data> fatherMap;
		//sizeMap表示的是当前集合(Data)的数据量的大小(如果有一个节点不是代表点,那么他的sizeMap将没有任何意义)
		public HashMap<Data, Integer> sizeMap;
		
		public UnionFindSet() {
			fatherMap = new HashMap<Data, Data>();
			sizeMap = new HashMap<Data, Integer>();
		}

		//我们用并查集的时候,我们一定是已经知道所有元素的,然后把这些元素先自己成为一个集合
		public void makeSets(List<Data> nodes) {
			fatherMap.clear();
			sizeMap.clear();
			for (Data node : nodes) {
				fatherMap.put(node, node);
				sizeMap.put(node, 1);
			}
		}

		//去找一个集合的代表点
		//并把沿途的所有节点的父节点都设成代表节点
		public Data findDaiBiao(Data node) {
			Data father = fatherMap.get(node);
			if (father != node) {
				father = findDaiBiao(father);
			}
			fatherMap.put(node, father);
			return father;
		}
		
		//查看这两个数是否属于一个集合
		public boolean isSameSet(Data a, Data b) {
			return findDaiBiao(a) == findDaiBiao(b);
		}
		
		//这个方法表示的是如果a和b不在一个集合上,这两个节点所在的集合进行合并
		//合并的过程就是先找另个节点所在集合的代表节点,若不是同一个则不在一个集合开始进行合并操作
		//合并操作就是先看谁的Size大就把另外一个集合的代表节点挂在另外一个大集合的代表节点的下面即可
		public void union(Data a, Data b) {
			if (a == null || b == null) {
				return;
			}
			Data aDaiBiao = findDaiBiao(a);
			Data bDaiBiao = findDaiBiao(b);
			if (aDaiBiao != bDaiBiao) {
				int aSetSize = sizeMap.get(aDaiBiao);
				int bSetSize = sizeMap.get(bDaiBiao);
				if (aSetSize <= bSetSize) {
					fatherMap.put(aDaiBiao, bDaiBiao);
					sizeMap.put(bDaiBiao, aSetSize + bSetSize);
				} else {
					fatherMap.put(bDaiBiao, aDaiBiao);
					sizeMap.put(aDaiBiao, aSetSize + bSetSize);
				}
			}
		}

	}

	public static void main(String[] args) {

	}

}

四、时间复杂度分析

对于并查集这个数据结构,如果这个并查集里有n个数据,总共查询+总共合并的次数就算达到O(n)以及以上了,甚至都n^2,n^3了那么他的单次查询或单次合并的平均时间复杂度仍然是为O(1)的。大牛从1964证到了1989,所以,证明就不说了,其实对于O(n)的总查询数+总合并数他就对应一个成长函数阿尔法n,这个成长函数成长速度非常慢,慢到当n->10^80(已知宇宙的的总原子数)的时候这个成长函数的值也不会超过6,so,他的单次查询或者合并的时间复杂度就是O(1)的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值