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

数据结构--并查集

作者: 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)
    

    相关文章

      网友评论

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

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