并查集
原创
©著作权归作者所有:来自51CTO博客作者放下也不自在的原创作品,请联系作者获取转载授权,否则将追究法律责任
import java.util.HashMap;
* 2)在并查集中最开始认为每个样本都在单独的集合里
* boolean isSameSet(V x,V y),查询两个样本是否属于一个集合
* void union(V x,V y),把各自所在的集合的所有样本合并成一个集合
* 4)isSameSet和union方法的代价越低越好
public class UnionSet<V> {
public HashMap<V, Node<V>> nodes;
public HashMap<Node<V>, Node<V>> parents;
public HashMap<Node<V>, Integer> sizeMap;
public UnionSet(List<V> values) {
Node<V> node = new Node<>(cur);
// 从点cur开始,一直往上找,找到不能再往上的代表点,返回
public Node<V> findFather(Node<V> cur) {
Stack<Node<V>> path = new Stack<>();
while (cur != parents.get(cur)) {
while (!path.isEmpty()) {
parents.put(path.pop(), cur);
public boolean isSameSet(V a, V b) {
return nodes.containsKey(a) && nodes.containsKey(b) && findFather(nodes.get(a)) == findFather(nodes.get(b));
public void union(V a, V b) {
if (!nodes.containsKey(a) || !nodes.containsKey(b)) {
Node<V> aHead = findFather(nodes.get(a));
Node<V> bHead = findFather(nodes.get(b));
int aSetSize = sizeMap.get(aHead);
int bSetSize = sizeMap.get(bHead);
Node<V> big = aSetSize >= bSetSize ? aHead : bHead;
Node<V> small = big == aHead ? bHead : aHead;
sizeMap.put(big, aSetSize + bSetSize);
// 如果两个user,a字段一样、或者b字段一样、或者c字段一样,就认为是一个人
public int mergeUsers(List<User> users) {
UnionSet<User> unionFind = new UnionSet<>(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));
if (mapB.containsKey(user.b)) {
unionFind.union(user, mapB.get(user.b));
if (mapC.containsKey(user.c)) {
unionFind.union(user, mapC.get(user.c));
return unionFind.getSetNum();
public User(String a, String b, String c) {