并查集的一个实现和优化

用C++实现了一个int类型的并查集,实现了三个版本,是逐个优化的一个过程

第一版

    // 第一版(采用一致id的形式,即p,q如果关联,则p, q的id一定完全一致)
    class UnionFind_1e {
    public:
        UnionFind_1e(int n) : count(n) {
            id.reserve(count + 1);
            for (int i = 0; i <= count; ++i) {
                id[i] = i;
            }
        }

        bool isConnected(int p, int q) {
            return find(p) == find(q);
        }

        void unionElements(int p, int q) {
            int pid = find(p);
            int qid = find(q);
            if (pid == qid) {
                return;
            }
            for (int i = 0; i <= count; ++i) {
                // 对同一组的数据需要全部逐个赋值,该动作效率较低
                if (id[i] == pid) {
                    id[i] = qid;
                }
            }
        }

    private:
        int find(int p) {
            assert(p >= 0 && p <= count);
            // 效率高
            return id[p];
        }

    private:
        std::vector<int> id;
        int count = 0;
    };

第二版

    // 第二版(采用parent的方式,即指向如果p,q关联,则值需要保证p, q最终的祖先一致就行)
    class UnionFind_2e {
    public:
        UnionFind_2e(int n) : count(n) {
            parent.reserve(count + 1);
            for (int i = 0; i <= count; ++i) {
                parent[i] = i;
            }
        }

        bool isConnected(int p, int q) {
            return find(p) == find(q);
        }

        void unionElements(int p, int q) {
            int proot = find(p);
            int qroot = find(q);
            if (proot == qroot) {
                return;
            }
            // 效率高
            parent[proot] = qroot;
        }

    private:
        int find(int p) {
            // 效率低,但是相对1e在unionElements中的逐个赋值效率要高
            while (p != parent[p]) {
                p = parent[p];
            }
            return p;
        }

    private:
        std::vector<int> parent;
        int count;
    };

第二版(层级优化)

    // 第二版(按照层级优化,即union的时候,将层级小的一方挂载到层级高的一方)
    class UnionFind_2e_rank {
    public:
        UnionFind_2e_rank(int n) : count(n) {
            parent.reserve(count + 1);
            for (int i = 0; i <= count; ++i) {
                parent[i] = i;
            }
            rank.resize(count + 1, 1);  // 初始每个的层级均为1
        }

        bool isConnected(int p, int q) {
            return find(p) == find(q);
        }

        void unionElements(int p, int q) {
            int proot = find(p);
            int qroot = find(q);
            if (proot == qroot) {
                return;
            }

            if (rank[proot] < rank[qroot]) {
                parent[proot] = qroot;
            } else if (rank[proot] > rank[qroot]) {
                parent[qroot] = proot;
            } else {
                // rank[proot] == rank[qroot]
                parent[proot] = qroot;
                ++rank[qroot];  // proot ”挂载“到qroot下面,本来两个层级一致,现在需要增加1
            }
        }

    private:
        int find(int p) {
            // 效率低,但是相对1e在unionElements中的逐个赋值效率要高
            while (p != parent[p]) {
                p = parent[p];
            }
            return p;
        }

    private:
        std::vector<int> parent;
        int count;
        std::vector<int> rank;
    };

第二版(数量优化)

    // 第二版(按照数量优化,即union的时候将数量少的一方挂载到数量多的一方)
    class UnionFind_2e_sz {
    public:
        UnionFind_2e_sz(int n) : count(n) {
            parent.reserve(count + 1);
            for (int i = 0; i <= count; ++i) {
                parent[i] = i;
            }
            sz.resize(count + 1, 1);  // 初始每个的数量均为1
        }

        bool isConnected(int p, int q) {
            return find(p) == find(q);
        }

        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] = qroot;
                sz[qroot] += sz[proot];  // 挂载到qroot后,需要将数量累加到qroot上面
            } else if (sz[proot] > sz[qroot]) {
                parent[qroot] = proot;
                sz[proot] += sz[qroot];
            } else {
                // sz[proot] == sz[qroot]
                parent[proot] = qroot;
                sz[qroot] += sz[proot];
            }
        }

    private:
        int find(int p) {
            // 效率低,但是相对1e在unionElements中的逐个赋值效率要高
            while (p != parent[p]) {
                p = parent[p];
            }
            return p;
        }

    private:
        std::vector<int> parent;
        int count;
        std::vector<int> sz;
    };

第三版(路径压缩)

    // 第三版(防止层级过高带来的查询性能,进行路径压缩优化)
    class UnionFind_3e {
    public:
        UnionFind_3e(int n) : count(n) {
            parent.reserve(count + 1);
            for (int i = 0; i <= count; ++i) {
                parent[i] = i;
            }
            rank.resize(count + 1, 1);  // 初始每个的层级均为1
        }

        bool isConnected(int p, int q) {
            return find(p) == find(q);
        }

        void unionElements(int p, int q) {
            int proot = find(p);
            int qroot = find(q);
            if (proot == qroot) {
                return;
            }

            if (rank[proot] < rank[qroot]) {
                parent[proot] = qroot;
            } else if (rank[proot] > rank[qroot]) {
                parent[qroot] = proot;
            } else {
                // rank[proot] == rank[qroot]
                parent[proot] = qroot;
                ++rank[qroot];  // proot ”挂载“到qroot下面,本来两个层级一致,现在需要增加1
            }
        }

    private:
        int find(int p) {
            // 效率低,但是相对1e在unionElements中的逐个赋值效率要高
            // 路径压缩优化实例
            // 假设有 4 -> 3 -> 2 -> 1 -> 0的指向,则通过路径压缩优化后变为
            // 1 -> 0
            // 3 -> 2 -> 0
            // 4 -> 2 -> 0
            while (p != parent[p]) {
                parent[p] = parent[parent[p]]; // 路径压缩优化,请细品
                p = parent[p];
            }
            return p;
        }

    private:
        std::vector<int> parent;
        int count;
        std::vector<int> rank;
    };

测试

   void test() {
        UnionFind_3e uf(9);
        uf.unionElements(0, 1);
        uf.unionElements(1, 2);
        uf.unionElements(7, 2);
        uf.unionElements(5, 2);
        uf.unionElements(5, 6);
        uf.unionElements(8, 3);
        uf.unionElements(3, 4);
        uf.unionElements(4, 9);

        assert(uf.isConnected(1, 6));
        assert(uf.isConnected(7, 6));
        assert(uf.isConnected(6, 0));
        assert(uf.isConnected(5, 0));
        assert(uf.isConnected(5, 7));
        assert(!uf.isConnected(8, 7));
        assert(!uf.isConnected(0, 9));
        assert(uf.isConnected(8, 4));
        assert(uf.isConnected(3, 9));
        return;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值