10.并查集结构

并查集

增删改查时间复杂度为O(1)的结构目前有哈希表跟并查集

  • 1)有若干个样本a、b、c、d…类型假设是V

  • 2)在并查集中一开始认为每个样本都在单独的集合里

  • 3)用户可以在任何时候调用如下两个方法:

    • boolean isSameSet(V x, V y):查询样本x和样本y是否属于一个集合
    • void union(V x, V y) :把x和y各自所在集合的所有样本合并成一个集合
  • 4)isSameSet和union方法的代价越低越好

  • 1)每个节点都有一条往上指的指针

  • 2)节点a往.上找到的头节点,叫做a所在集合的代表节点

  • 3)查询x和y是否属于同一个集合,就是看看找到的代表节点是不是一个

  • 4)把x和y各自所在集合的所有点合并成一个集合,只需要小集合的代表点挂
    在大集合的代表点的下方即可

并查集的优化
  • 1)节点往上找代表点的过程,把沿途的链变成扁平的
  • 2)小集合挂在大集合的下面
  • 3)如果方法调用很频繁,那么单次调用的代价为O(1),两个方法都如此
并查集的应用
  • 解决两大块区域的合并问题
  • 常用在图等领域中
并查集核心代码
package com.harrison.class10;

import java.util.HashMap;
import java.util.List;
import java.util.Stack;

public class Code01_UnionFind {
    
    
	public static class Node<V> {
    
    
		V value;

		public Node(V v) {
    
    
			value = v;
		}
	}

	public static class UnionFind<V> {
    
    
		public HashMap<V, Node<V>> nodes;
		public HashMap<Node<V>, Node<V>> parents;
		public HashMap<Node<V>, Integer> sizeMap;

		public UnionFind(List<V> values) {
    
    
			nodes = new HashMap<>();
			parents = new HashMap<>();
			sizeMap = new HashMap<>();
			for (V cur : values) {
    
    
				Node<V> node = new Node<>(cur);
				nodes.put(cur, node);
				parents.put(node, node);
				sizeMap.put(node, 1);
			}
		}

		public Node<V> findFather(Node<V> cur) {
    
    
			Stack<Node<V>> path = new Stack<>();
			while(cur!=parents.get(cur)) {
    
    
				path.push(cur);
				cur=parents.get(cur);
			}
			while(!path.isEmpty()) {
    
    
				parents.put(path.pop(),cur);
			}
			return cur;
		}
		
		public boolean isSameSet(V a,V b) {
    
    
			return findFather(nodes.get(a))==findFather(nodes.get(b));
		}
		
		public void union(V a, V b) {
    
    
			Node<V> aHead=findFather(nodes.get(a));
			Node<V> bHead=findFather(nodes.get(b));
			if(aHead!=bHead) {
    
    
				int aSetSize=sizeMap.get(aHead);
				int bSetSize=sizeMap.get(bHead);
			    Node<V> big= aSetSize>=bSetSize?aHead:bHead;
			    Node<V> small= big==aHead?bHead:aHead;
			    parents.put(small, big);
			    sizeMap.put(big, aSetSize+bSetSize);
			    sizeMap.remove(small);
 			}
		}
		
		public int sets() {
    
    
			return sizeMap.size();
		}
	}

}
【题目】

如果两个user,a字段一样、或者b字段一样、或者c字段一样,就认为是一个人。请合并users,返回合并之后的用户数量

package com.harrison.class10;

import java.util.HashMap;
import java.util.List;
import java.util.Stack;

public class Code02_MergeUsers {
    
    
	public static class User {
    
    
		public String a;
		public String b;
		public String c;

		public User(String a, String b, String c) {
    
    
			this.a = a;
			this.b = b;
			this.c = c;
		}
	}

	public static class Node<V> {
    
    
		V value;

		public Node(V v) {
    
    
			value = v;
		}
	}

	public static class UnionFind<V> {
    
    
		public HashMap<V, Node<V>> nodes;
		public HashMap<Node<V>, Node<V>> parents;
		public HashMap<Node<V>, Integer> sizeMap;

		public UnionFind(List<V> values) {
    
    
			nodes = new HashMap<>();
			parents = new HashMap<>();
			sizeMap = new HashMap<>();
			for (V cur : values) {
    
    
				Node<V> node = new Node<>(cur);
				nodes.put(cur, node);
				parents.put(node, node);
				sizeMap.put(node, 1);
			}
		}

		public Node<V> findFather(Node<V> cur) {
    
    
			Stack<Node<V>> path = new Stack<>();
			while (cur != parents.get(cur)) {
    
    
				path.push(cur);
				cur = parents.get(cur);
			}
			while (!path.isEmpty()) {
    
    
				parents.put(path.pop(), cur);
			}
			return cur;
		}

		public boolean isSameSet(V a, V b) {
    
    
			return findFather(nodes.get(a)) == findFather(nodes.get(b));
		}

		public void union(V a, V b) {
    
    
			Node<V> aHead = findFather(nodes.get(a));
			Node<V> bHead = findFather(nodes.get(b));
			if (aHead != bHead) {
    
    
				int aSetSize = sizeMap.get(aHead);
				int bSetSize = sizeMap.get(bHead);
				Node<V> big = aSetSize >= bSetSize ? aHead : bHead;
				Node<V> small = big == aHead ? bHead : aHead;
				parents.put(small, big);
				sizeMap.put(big, aSetSize + bSetSize);
				sizeMap.remove(small);
			}
		}

		public int getSizeNum() {
    
    
			return sizeMap.size();
		}
	}

	// 如果两个user,a字段一样、或者b字段一样、或者c字段一样,就认为是一个人
	// 请合并users,返回合并之后的用户数量
	public static int mergeUsers(List<User> users) {
    
    
		UnionFind<User> unionFind = new UnionFind<>(users);
		HashMap<String, User> mapA = new HashMap<>();
		HashMap<String, User> mapB = new HashMap<>();
		HashMap<String, User> mapC = new HashMap<>();
		for (User user : users) {
    
    
			if (mapA.containsKey(user.a)) {
    
    
				unionFind.union(user, mapA.get(user.a));
			}else {
    
    
				mapA.put(user.a, user);
			}
			if (mapB.containsKey(user.b)) {
    
    
				unionFind.union(user, mapB.get(user.b));
			}else {
    
    
				mapB.put(user.b, user);
			}
			if (mapC.containsKey(user.c)) {
    
    
				unionFind.union(user, mapC.get(user.c));
			}else {
    
    
				mapC.put(user.c, user);
			}
		}
		//向并查集询问,合并之后,还有多少个集合
		return unionFind.getSizeNum();
	}

}

猜你喜欢

转载自blog.csdn.net/weixin_44337241/article/details/121207843
10.
今日推荐