算法/数据结构/并查集

并查集常用来解决连通性问题:

其实是一种n叉树的结构;

在图里: 比如我们要查两个节点是否连着,如果连着我们就可以用isSame找出来就好了;

大白话就是当我们需要判断两个元素是否在同一个集合里的时候,我们就要想到用并查集。

并查集主要有两个功能:

  • 将两个元素添加到一个集合中。 join;

  • 判断两个元素在不在同一个集合 isSame;

接下来围绕并查集的这两个功能来展开讲解。

//

并查集作为一种数据结构,我们要在原有基础上创建它,首先就需要建立一个数组father和一个代表树高度的rank数组,初始无值进入的时候自然是0高度;

vector<int> father(n);
vector<int> rank(n);

如果我们要把两个元素加入一个集合中(或者两个点连成一条线)

这里要注意一个问题,u和v会变成自己的根,然后在根相连;

// 将v,u 这条边加入并查集,v的根成u
void join(int u, int v) {
    u = find(u); // 寻找u的根
    v = find(v); // 寻找v的根
    if (u == v) return; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
    father[v] = u;
}

节点的根本身先设置为自己,也就是init初始化

void init(int n){
    for(int i=0;i<n;i++){
        father[i]=i;
    }
}

判断是不是在一个集合里(一张图里)

    bool isSame(int u,int v){
        u=find(u);//找u的根;
        v=find(v);//找v的根;
        return u==v;
    };

寻根操作+路径压缩(把这条路径上的所有节点都指向根;比如1->2->3,作为树来看1是根节点,那么我们让3的根也为1,1->2,1->3);

      //如果u是自己的根,那么就返回自己
      //如果不是,那么u就逐渐指向根
    int find(int u){
        return u==father[u]?u:father[u]=find(father[u]);
    }

rank操作是在merge里实现的:rank操作:如果两个点进行合并,如何判断谁是谁的爹是一个问题,我们认为,一个树的左右树高度差越小是进化,如果合并后的树左右子树高度差变大了就是退化,因此,我们才需要统计rank的必要;

 void merge/join(int x,int y){
    //找到根节点,因为都是根节点做连接操作;
    x=find(x);
    y=find(y);
    //如果根节点相等,说明已经在一个树上了,那么就没必要操作了,高度也不会加;
    if(x==y) return;
    if(rank(x)>rank(y)) father[y]=x; //选择高度高的根为新的根节点,并且高度不会发生变化;
    else{
        if(rank(x)==rank(y)){
            father[x]=y; //一样没有区别,就按照else的写法来
            rank[y]++;
        }
        else father[x]=y; //高度不变;            
    }
    return;
}

并查集构建方法2:设置结构体 

注意,在结构体末尾直接加上一个名字就创建了这个名字的对象;

    struct DisjointSet{
        int father[MAX_N];
        //初始化
        DisjointSet(){
            for(int i=0;i<MAX_N;i++){
                father[i]=i;
            }
        }
        int find(int u){
            //这个逻辑处理错了就写错了,如果u是自己的根,就返回自己,如果不是,那么就返回他的爹,并且查询他的爹的根是不是自己,如果不是就往下走返回根节点;
            return u==father[u]?u:father[u]=find(father[u]);
        }
        //就是join,
        void join(int u,int v){
            u=find(u);
            v=find(v);
            if(u==v) return;
            father[u]=v;
        }
        void merge(int u,int v){
            father[find(u)]=find(v);
        }
        bool isSame(int u,int v){
            u=find(u);
            v=find(v);
            return u==v;
        }
    } ds;

1971. 寻找图中是否存在路径

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值