并查集 Disjoint Set Union (DSU)

并查集 Disjoint Set Union (DSU)

在这里插入图片描述

并查集的功能

  1. 将两个集合合并
  2. 询问两个元素是否在一个集合当中

基本原理

每个集合用一棵树来表示。树的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点。

三个问题

  • 如何判断树根 p[x] = x
  • 如何求元素x的根节点 while(p[x] != x) x = p[x]
  • 如何合并两个集合,比如合并元素xy所在的集合 找到x的根节点p[x]p[y]的根节点p[y]p[px] = py

并查集核心操作find()

数组p[N]当中保存的是结点x的父元素,也就是p[x]

在这里插入图片描述

形式如同上图,每个结点都记录父元素的下标值,而跟结点的信息是元素所在集合的信息。

如果要想要寻找结点x属于那个集合,就需要不断向上寻找双亲的信息,最终找到根结点,也就是集合的信息。

在寻找集合信息的过程中,可以进行优化:
在这里插入图片描述

假设我们需要寻找x的所在集合,就需要不断的向上寻找父结点,判断父结点的信息,最后找到根结点也就是集合信息为止。但是在此过程中,可以将中途遍历过的结点的父结点信息都替换成根结点的信息,这样在下次查询的时候就可以直接访问x的父结点,将时间复杂度降低致O(1)

所以 find()需要实现两个操作 :

  1. 寻找集合信息
  2. 将路径压缩
// p[N]用作保存树的各个结点的信息

// 迭代写法
public static int find(int x ){
    //因为p[x]中存的是x的父节点的索引 所以一直迭代找到 x = p[x]的节点 即根节点(祖宗节点) 
    int r = x;
    while(r != p[r]) r = p[r];
       
    //路径压缩 将这一条路上的所有节点都直接指向根节点(祖宗节点) 此时的r就是祖宗节点
    while(x != p[x]){
        //存一下父节点
        int t = p[x];
        //直接指向根节点
        p[x] = r;
        //走到存储的父节点的位置继续做 
        x = t;
    }
    return r;
}
// 递归写法
public static int find(int x) { // 合并 + 压缩过程
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

模板题

acwing 836. 合并集合

acwing 837. 连通块中点的数量 (需要根据题目信息额外维护一些信息)

acwing 240. 食物链(需要根据题目信息额外维护一些信息)

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神烦狗闯入了你的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值