美文网首页
数据结构--并查集

数据结构--并查集

作者: Hayley__ | 来源:发表于2021-04-19 18:33 被阅读0次

并查集

由孩子指向父亲,快速判断节点连接状态。可用于解决连接问题,就集合的并集。


集合
//interface
public interface UnionFind {
    int getSize();
    boolean isConnected(int p, int q);
    void unionElements(int p, int q);
}
public class UnionFind1 implements UnionFind {

    private int[] id;

    public UnionFind1(int size) {
        id = new int[size];
        //每个元素都所属不同的集合
        for (int i = 0; i < id.length; i++) {
            id[i] = i;
        }
    }

    @Override
    public int getSize() {
        return id.length;
    }

    //查找元素p所对应的集合编号
    private int find(int p){
        if (p < 0 && p >= id.length)
            throw new IllegalArgumentException("p is out of bound");
        return id[p];
    }

    //查看元素p与q是否属于同一个集合 O(1)
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    //合并元素p与元素q所属的集合  O(n)
    @Override
    public void unionElements(int p, int q) {
        int pId = find(p);
        int qId = find(q);

        if(pId == qId)
            return;

        for (int i = 0; i < id.length; i++) {
            if (id[i] == pId)
                id[i] = qId;
        }
    }
}

//时间复杂度 O(log^*n) 近乎于O(1)

优化一

孩子指向父亲,依然用数组表示,但是形成的是树结构。


union

仍然可以使用数组表示


初始状态
union
public class UnionFind2 implements UnionFind {

    private int[] parent;

    public UnionFind2(int size) {
        parent = new int[size];

        for (int i = 0; i < size; i++) {
            parent[i] = i;
        }
    }

    @Override
    public int getSize() {
        return parent.length;
    }

    //查找过程,查找元素p所对应的集合编号
    //O(h)复杂度,h为树的高度
    private int find(int p) {

        if (p < 0 && p >= parent.length)
            throw new IllegalArgumentException("p is out of bound");

        while (p != parent[p])
            p = parent[p];
        return p;

    }

    //O(h)复杂度,h为树的高度
    //查看元素p与q是否属于同一个集合 O(1)
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    //O(h)复杂度,h为树的高度
    //合并元素p与元素q所属的集合  O(n)
    @Override
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);

        if (pRoot == qRoot)
            return;

        parent[pRoot] = parent[qRoot];
    }
}

优化二

让节点个数少的根节点指向节点个数多的根节点。


优化二
public class UnionFind3 implements UnionFind {

    private int[] parent;
    private int[] sz;

    public UnionFind3(int size) {

        parent = new int[size];

        //sz[i]表示以i为根的集合中元素个数
        sz = new int[size];

        for (int i = 0; i < size; i++) {
            parent[i] = I;
            sz[i] = 1;
        }
    }

    @Override
    public int getSize() {
        return parent.length;
    }

    //查找过程,查找元素p所对应的集合编号
    //O(h)复杂度,h为树的高度
    private int find(int p) {

        if (p < 0 && p >= parent.length)
            throw new IllegalArgumentException("p is out of bound");

        while (p != parent[p])
            p = parent[p];
        return p;

    }

    //O(h)复杂度,h为树的高度
    //查看元素p与q是否属于同一个集合 O(1)
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    //O(h)复杂度,h为树的高度
    //合并元素p与元素q所属的集合  O(n)
    @Override
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);

        if (pRoot == qRoot)
            return;

        //根据俩个元素所在树的元素个数不同判断合并方向
        //将元素个数少的集合合并到元素个数多的集合上
        if(sz[pRoot] < sz[qRoot]) {
            parent[pRoot] = parent[qRoot];
            sz[qRoot] += sz[pRoot];
        }
        else { // sz[pRoot] >= sz[qRoot]
            parent[qRoot] = parent[pRoot];
            sz[pRoot] += sz[qRoot];
        }
    }
}

//时间复杂度 O(log^*n) 近乎于O(1)

优化三

基于rank的优化,rank[i]表示根节点为i的树的高度。
让深度比较少的树向深度比较高的树进行合并。

优化三
public class UnionFind4 implements UnionFind {

    private int[] parent;
    private int[] rank;

    public UnionFind4(int size) {

        parent = new int[size];

        //rank[i]表示以i为根的集合所表示的树的层数
        rank = new int[size];

        for (int i = 0; i < size; i++) {
            parent[i] = I;
            rank[i] = 1;
        }
    }

    @Override
    public int getSize() {
        return parent.length;
    }

    //查找过程,查找元素p所对应的集合编号
    //O(h)复杂度,h为树的高度
    private int find(int p) {

        if (p < 0 && p >= parent.length)
            throw new IllegalArgumentException("p is out of bound");

        while (p != parent[p])
            p = parent[p];
        return p;

    }

    //O(h)复杂度,h为树的高度
    //查看元素p与q是否属于同一个集合 O(1)
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    //O(h)复杂度,h为树的高度
    //合并元素p与元素q所属的集合  O(n)
    @Override
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);

        if (pRoot == qRoot)
            return;

        //根据俩个元素所在树的rank不同判断合并方向
        //将rank低的集合合并到rank高的集合上
        if(rank[pRoot] < rank[qRoot]) {
            parent[pRoot] = parent[qRoot];
        } else if (rank[pRoot] > rank[qRoot]) {
            parent[qRoot] = parent[pRoot];
        }
        else { // =
            parent[qRoot] = parent[pRoot];
            rank[pRoot] += 1;
        }
    }
}

//时间复杂度 O(log^*n) 近乎于O(1)

优化四

路径压缩,将高树压缩成矮树


优化四
4.1
4.2
4.3
public class UnionFind5 implements UnionFind {

    private int[] parent;
    private int[] rank;

    public UnionFind5(int size) {

        parent = new int[size];

        //rank[i]表示以i为根的集合所表示的树的层数
        rank = new int[size];

        for (int i = 0; i < size; i++) {
            parent[i] = I;
            rank[i] = 1;
        }
    }

    @Override
    public int getSize() {
        return parent.length;
    }

    //查找过程,查找元素p所对应的集合编号
    //O(h)复杂度,h为树的高度
//    private int find(int p) {
//
//        if (p < 0 && p >= parent.length)
//            throw new IllegalArgumentException("p is out of bound");
//
//        while (p != parent[p])
//            p = parent[p];
//        return p;
//    }


    //优化 路径压缩 经典优化思路
    //查找过程,查找元素p所对应的集合编号
    //O(h)复杂度,h为树的高度
    private int find(int p) {

        if (p < 0 && p >= parent.length)
            throw new IllegalArgumentException("p is out of bound");

        //没有改变rank 使用粗略的rank值已经能满足性能
        while (p != parent[p])
            parent[p] = parent[parent[p]];
            p = parent[p];
        return p;
    }

    //O(h)复杂度,h为树的高度
    //查看元素p与q是否属于同一个集合 O(1)
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    //O(h)复杂度,h为树的高度
    //合并元素p与元素q所属的集合  O(n)
    @Override
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);

        if (pRoot == qRoot)
            return;

        //根据俩个元素所在树的rank不同判断合并方向
        //将rank低的集合合并到rank高的集合上
        if(rank[pRoot] < rank[qRoot]) {
            parent[pRoot] = parent[qRoot];
        } else if (rank[pRoot] > rank[qRoot]) {
            parent[qRoot] = parent[pRoot];
        }
        else { // =
            parent[qRoot] = parent[pRoot];
            rank[pRoot] += 1;
        }
    }
}

//时间复杂度 O(log^*n) 近乎于O(1)

优化五

使用递归,将查询的节点,以及其之前的节点都直接指向跟节点


优化五
public class UnionFind6 implements UnionFind{

    private int[] parent;
    private int[] rank;

    public UnionFind6(int size) {

        parent = new int[size];

        //rank[i]表示以i为根的集合所表示的树的层数
        rank = new int[size];

        for (int i = 0; i < size; i++) {
            parent[i] = i;
            rank[i] = 1;
        }
    }

    @Override
    public int getSize() {
        return parent.length;
    }

    //优化 路径压缩 经典优化思路
    //查找过程,查找元素p所对应的集合编号
    //O(h)复杂度,h为树的高度
    private int find(int p) {

        if (p < 0 && p >= parent.length)
            throw new IllegalArgumentException("p is out of bound");

        if (p != parent[p])
            parent[p] = find(parent[p]);
        return parent[p];
    }

    //O(h)复杂度,h为树的高度
    //查看元素p与q是否属于同一个集合 O(1)
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    //O(h)复杂度,h为树的高度
    //合并元素p与元素q所属的集合  O(n)
    @Override
    public void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);

        if (pRoot == qRoot)
            return;

        //根据俩个元素所在树的rank不同判断合并方向
        //将rank低的集合合并到rank高的集合上
        if(rank[pRoot] < rank[qRoot]) {
            parent[pRoot] = parent[qRoot];
        } else if (rank[pRoot] > rank[qRoot]) {
            parent[qRoot] = parent[pRoot];
        }
        else { // =
            parent[qRoot] = parent[pRoot];
            rank[pRoot] += 1;
        }
    }
}
//时间复杂度 O(log^*n) 近乎于O(1)

相关文章

  • 并查集

    并查集 并查集是什么 并查集是一种用来管理元素分组情况的数据结构,并查集可以高效地进行如下操作: 查询元素a和元素...

  • 并查集

    并查集是什么 并查集是一种用来管理元素分组情况的数据结构。并查集可以高效地进行如下操作。不过需要注意并查集虽然可以...

  • Union-Find algorithm-并查集算法

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

  • 高级数据结构:并查集(Java 实现)

    并查集的内容非常简单,代码的每个方法的实现都很短,难在灵活应用。 并查集基础 为什么叫并查集?因为在这个数据结构中...

  • 最小生成树算法——Kruskal算法

    算法思想 先了解下什么叫并查集 并查集 (Union Find Set)又叫不相交集数据结构(Disjointed...

  • luogu P1551 亲戚(并查集入门)

    这是一个并查集模板。 说一下并查集,虽然我也是刚刚学会没几天。。。 并查集是个树形结构的数据结构,主要用于合并两个...

  • markdown学习

    #并查集 ##并查集的定义 ##并查集的操作

  • 数据结构——并查集

    目录 1、等价关系和等价类 2、并查集实现中的权衡 2.1、快速FIND实现(Quick FIND) 2.2、快速...

  • 数据结构 - 并查集

    相关概念 等价关系若对于每一对元素(a, b), ![](http://latex.codecogs.com/sv...

  • 数据结构-并查集

    并查集 洛谷(P3367) 在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集...

网友评论

      本文标题:数据结构--并查集

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