并查集

并查集主要是为了解决图的动态连通性的问题,主要需要实现union、find的操作,基本的C++实现如下:

class UnionFind{
    private:
    int count; //记录连通分量的个数
    vector<int> parent;
    public:
    UnionFind(int n){
        count = n;
        parent = vector<int>(n,0);
        for(int i = 0; i < n; i++){
            parent[i] = i; //自己指向自己
        }
    }
    //将p和q进行合并
    void Union(int p, int q){
        int rootP = Find(p);
        int rootQ = Find(q);
        if(rootP == rootQ){
            return;
        }
        //简单的将p的根指向q的根
        parent[rootP] = rootQ;
        count--;
    }
    //找到p的根
    int Find(int p){
        while(parent[p] != p){
            p = parent[p];
        }
        return p;
    }
    bool isConnected(int p, int q){
        return Find(p) == Find(q);
    }
    int Count(){
        return count;
    }
};

上述的实现在union的时候,只是简单的将一个根指向另一个根,会造成树的深度过深,在find操作的时候效率低下,在并查集讲解中有更详尽的介绍。一般有两个优化union的方法,一是将元素少的集合的根节点指向元素多的集合的根节点,如下图将9指向8,而不是将8指向9。具体实现如下所示:
在这里插入图片描述

void Union(int p, int q){
        int rootP = Find(p);
        int rootQ = Find(q);
        if(rootP == rootQ)
            return;
        //进行优化 --->将元素少的集合并到元素多的集合
        if(size[rootP] < size[rootQ]){
            parent[rootP] = rootQ;
            size[rootQ] += size[rootP];
        }else{
            parent[rootQ] = rootP;
            size[rootP] += size[rootQ];
        }
        //两个分量合二为一
        count--;
    }

如果按照上面的方法对下图进行合并,则4的根8指向了2的根7,深度为4。但是更好的做法是将2的根7指向4的根8,深度为3。因此另一种优化是将集合中深度小的根指向集合中深度大的根。具体实现如下:
在这里插入图片描述

    void Union(int p, int q){
        int rootP = Find(p);
        int rootQ = Find(q);
        if(rootP == rootQ)
            return;
        //进行优化 --->将深度小的指向深度大的
        if(rank[rootP] < rank[rootQ]){
            parent[rootP] = rootQ;
        }else if(rank[rootP] > rank[rootQ]){
            parent[rootQ] = rootP;
        }else{
            parent[rootP] = rootQ;
            rank[rootQ] += 1; //当层数相同的时候,更新rank
        }
        //两个分量合二为一
        count--;
    }

刚才我们关注点在union操作上,其实find操作也可以优化,之前的实现就是一直往上遍历进行寻找。因为我们关注点是找到根,因此可以跳着找,具体实现如下:
在这里插入图片描述

 int Find(int p){
        while(parent[p] != p){
            //进行路径压缩
            parent[p] = parent[parent[p]];
            p = parent[p];
        }
        return p;
    }

还有一种find的优化方式:将每个元素直接指向根,在查找的时候就只查找一次就可以了。
在这里插入图片描述

 //返回p的根节点
    int Find(int p){
        while(parent[p] != p){
            //更进一步进行路径压缩
            parent[p] = Find(parent[p]);
        }
        return parent[p];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值