美文网首页
并查集(Union-find Set)及java实现

并查集(Union-find Set)及java实现

作者: longLiveData | 来源:发表于2020-05-06 09:41 被阅读0次

并查集

并查集处理集合之间的关系,即 'union'合并 和 'find'查找。
在这种数据类型中,N个不同元素被分成若干个组,每组是一个集合,这种集合叫做分离集合。
并查集支持查找一个元素所属的集合和两个元素分别所属的集合的合并。

并查集支持的操作
MAKE(X): 建立一个仅有成员X的新集合。
UNION(X,Y):将包含X和Y的动态集合合并为一个新集合S,此后该二元素处于同一集合。
FIND(X):返回一个包含X的集合。
注意:并查集只能进行合并操作,不能进行分割操作。

并查集实现原理
并查集是使用树结构实现的:
1.初始化:准备N个节点来表示N个元素,最开始没有边。
2.合并:从一个组的根向另一个组的根连边,这样两棵树就变为了一棵树,也就把两个组合并为一个组了。
3.查询:查询两个节点是否在同一个组,只需要查询他们是否具有相同的根。

注意:
(1)为避免树的退化,对于每棵树,记录其高度rank。
(2)如果合并时两棵树高度不同,那么从rank小的向rank大的连边。
(3)为了简化后续查询,在查询某个节点时,一旦向上走到了一次根节点,就把这个节点到父亲的边改为直接连向根。不仅指查询的节点,也包括查询过程中经过的节点。使用这种简化的方法时,即使树的高度发生了改变,我们也不修改rank值。

并查集的复杂度
对N个元素并查集进行的一次操作的复杂度是O(α(N)),α(N)是阿克曼函数的反函数。这个复杂度是比O(LogN)还要快的。

java实现

import java.util.HashMap;
import java.util.List;
import java.util.Arrays;

public class UnionFind<E> {
    private HashMap<E,E> parent = null; // 一棵树表示一个集合
    private HashMap<E,Integer> rank = null;  // 记录树高度信息,避免树退化
    private int count = 0; // 集合数

    public UnionFind(List<E> list) {
        parent = new HashMap<>();
        rank = new HashMap<>();
        count = list.size();
        for ( E e : list ) {
            parent.put(e, e);
            rank.put(e, 0);
        }
    }

    public HashMap<E, E> parent() {
        return parent;
    }

    public HashMap<E, Integer> rank() {
        return rank;
    }

    public int numSubsets() {
        return count;
    }

    // 查找元素
    public E find(E e) {
        E pe = parent.get(e);
        while ( ! pe.equals(e) ) {
            parent.put(e, parent.get(pe)); // 将该节点到父亲的边更新为直接连向根,方便后续查询
            e = parent.get(e);
            pe = parent.get(e);
        }
        return e;
    }

  // 合并两个节点所在的集合
    public void union(E e1, E e2) {
        E root1 = find(e1), root2 = find(e2);
        // 若两个节点在同一个节点(根相同)则不合并
        if ( root1.equals(root2) ) {
            return;
        }
        // 按照树高rank,将低的连到高的, 树高不变
        if ( rank.get(root1) < rank.get(root2) ) {
            parent.put(root1, root2);
        }
        else if ( rank.get(root1) > rank.get(root2) ) {
            parent.put(root2, root1);
        }
        // 若两棵树高度相同,连后高度+1
        else {
            parent.put(root2, root1);
            rank.put(root1, 1 + rank.get(root1));
        }
        count--; // 连后树数量-1
    }

    public static void main(String[] args) {
        System.out.println("初始化: ");
        String[] labels = {"a", "b", "c", "d", "e", "f", "g", "h"};
        UnionFind<String> uf = new UnionFind<>(Arrays.asList(labels));
        System.out.println("uf.parent() = " + uf.parent());
        System.out.println("uf.rank() = " + uf.rank());
        System.out.println("count = " + uf.numSubsets());

        System.out.println("join b & e, c & d 之后: ");
        uf.union("b", "e");
        uf.union("c", "d");
        System.out.println("uf.parent() = " + uf.parent());
        System.out.println("uf.rank() = " + uf.rank());
        System.out.println("count = " + uf.numSubsets());

        System.out.println("join e & h, a & g, h & c 之后: ");
        uf.union("e", "h");
        uf.union("a", "g");
        uf.union("h", "c");
        System.out.println("uf.parent() = " + uf.parent());
        System.out.println("uf.rank() = " + uf.rank());
        System.out.println("count = " + uf.numSubsets());

        System.out.println("join f & g 之后:");
        uf.union("f", "g");
        System.out.println("uf.parent() = " + uf.parent());
        System.out.println("uf.rank() = " + uf.rank());
        System.out.println("count = " + uf.numSubsets());
    }
}

输出结果为:

初始化: 
uf.parent() = {a=a, b=b, c=c, d=d, e=e, f=f, g=g, h=h}
uf.rank() = {a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0}
count = 8
join b & e, c & d 之后: 
uf.parent() = {a=a, b=b, c=c, d=c, e=b, f=f, g=g, h=h}
uf.rank() = {a=0, b=1, c=1, d=0, e=0, f=0, g=0, h=0}
count = 6
join e & h, a & g, h & c 之后: 
uf.parent() = {a=a, b=b, c=b, d=c, e=b, f=f, g=a, h=b}
uf.rank() = {a=1, b=2, c=1, d=0, e=0, f=0, g=0, h=0}
count = 3
join f & g 之后:
uf.parent() = {a=a, b=b, c=b, d=c, e=b, f=a, g=a, h=b}
uf.rank() = {a=1, b=2, c=1, d=0, e=0, f=0, g=0, h=0}
count = 2

相关文章

  • Union-Find algorithm-并查集算法

    并查集 并查集(Union-Find Set),也称为不相交集数据结构(Disjointed Set Data S...

  • 并查集(Union-find Set)及java实现

    并查集 并查集处理集合之间的关系,即 'union'合并 和 'find'查找。在这种数据类型中,N个不同元素被分...

  • union find

    参考 并查集(disjoint set)的实现及应用

  • 算法分析与设计 并查集

    并查集学习笔记 并查集(union-find set)是一抽象数据类型。它所处理的是“集合”之间的关系,即动态地维...

  • 并查集(Union-find set) 2020-04-08(未

    啥是并查集(Union-find set) 并查集是用于合并集合的一种树形的逻辑数据结构,实际上底层通过【数组】实...

  • Union-Find Set 并查集

    ![TOC] 并查集操作的复杂度是log n。是一个衰减非常快的函数,即使n 很大,log n的结果也接近一个常数...

  • 接触并查集结构

    概述 并查集(Disjoint set或者Union-find set)是一种树型的数据结构(一定要一次性给定数据...

  • 并查集问题

    并查集(Union-find or Disjoint-set)问题是一个很有趣现实中很常见的问题,也并不是一个能够...

  • 第七周算法总结

    1.字典集 手动实现trie类 search方法 insert 方法 2.并查集 disjoint set 判断是...

  • 并查集 Java实现

    算法题目 力扣 <连通网络的操作次数>[https://leetcode-cn.com/problems/numb...

网友评论

      本文标题:并查集(Union-find Set)及java实现

      本文链接:https://www.haomeiwen.com/subject/ickightx.html