Java 并查集代码

public class UnionFind<V> {

    private class Node<V> {
        V value;
        public Node(V v) {
            value = v;
        }
    }
    
    // 元素与节点对应关系
    private HashMap<V, Node<V>> nodes;
    // 节点与父节点对应关系
    private HashMap<Node<V>, Node<V>> parents;
    // 根节点与根节点所在集合大小的对应关系
    private 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;
    }

    // a 与 b 是否在同一个集合
    public boolean isSameSet(V a, V b) {
        return findFather(nodes.get(a)) == findFather(nodes.get(b));
    }

    // 合并 a 与 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 size() {
        return sizeMap.size();
    }

}

模版

public static class UnionFind {
    
    int[] parent; // parent[i] = k,i 的父亲是 k    
    int[] size; // i 所在的集合大小是多少    
    int sets; // 并查集内有多少个集合    
    int[] stack; // 数组模拟栈

    public UnionFind(int N) {
        parent = new int[N];
        size = new int[N];
        stack = new int[N];
        sets = N;
        for (int i = 0; i < N; i++) {
            parent[i] = i;
            size[i] = 1;
        }
    }

    // 从i开始一直往上,往上到不能再往上,代表节点,返回
    private int find(int i) {
        int top = 0; 
        while (i != parent[i]) {
            stack[top++] = i;
            i = parent[i];
        }
        for (top--; top >= 0; top--) { // 路径压缩
            parent[stack[top]] = i;
        }
        return i;
    }

    public void union(int i, int j) {
        int f1 = find(i);
        int f2 = find(j);
        if (f1 != f2) {
            int max = size[f1] > size[f2] ? f1 : f2;
            int min = max == f1 ? f2 : f1;
            size[max] += size[min];
            parent[min] = max;
            sets--;
        }
    }
    
	public boolean isSameSet(int i, int j) {
        return find(i) == find(j);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值