并查集详解

讲并查集之前,先给大家一个并查集模板的题目;
题目链接

最简单版的并查集

之前看别的blog的时候,看到过一个有趣的比喻,假设开始的每个人都自立帮派,每个人就是一个帮派,他就是这个帮派的代表,
假设下图每个元素都代表一个个人,即帮派代表和帮派(相当于初始化每个元素的父节点就是自己)。
在这里插入图片描述
然后元素1和元素3两个帮派进行决斗,每个帮派派出自己的代表作战,即1和3,比试结果是1赢了,3输了,所以1帮派和3帮派合并,此时的帮派代表变成了1.
在这里插入图片描述
假如此时的2想和3决斗,但是这是帮派间的决斗,所以要派出帮派的代表,即变成了1和2的决斗,结果1赢了2,1把2收入麾下,此时2所在帮派加入了1所在的帮派。
在这里插入图片描述
假设4和5和6同理,最后就剩下1所在和帮派和4所在的帮派了。
在这里插入图片描述
现在1和4所在的帮派决斗,各自派出自己的代表即宗主(也就是父节点),出战。
结果1又赢了,所以此时4所在的帮派成员全部加入到1所在的帮派。
在这里插入图片描述
相信看完以后就可以理解了,下面用三个函数来表示上述过程。
第一个函数是初始化每个元素的父节点为其自身。

void init(int n)//初始化,每个元素的父节点是自己
{
    for(int i=1;i<=n;i++)
        fa[i]=i;
}

第二个函数是查找父节点的函数。

int findx(int x)//找到父节点
{
    if(fa[x]==x)
        return x;
    else
        return findx(fa[x]);
}

第三个函数是合并函数

void mergex(int i,int j)
{
    fa[findx(i)]=findx(j);
}

以上便是简单版的并查集,时间复杂度由树的深度决定。

路径压缩版的并查集

路径压缩版的并查集,就是逐渐修改元素的父节点,最终有将所有的元素全部指向树的头节点的可能。
图形大致是这样。
在这里插入图片描述
那么,怎么用函数实现呢??
其实就是改了查找函数,在查找函数中不断更新父节点。

int findx(int x)//找到父节点
{
return fa[x]==x?x:(fa[x]=findx(fa[x]));
}

并查集按秩合并

下面,我问大家一个问题,对于下图,是让7合并上8,还是让8合并上7?
在这里插入图片描述
答案是肯定的,是让8合并上7,如果让7合并上8,无疑会增大树的深度。所以我们在合并的时候,要按秩合并。
那么这个怎么操作呢??
其实只需要弄多一个记录数的深度的数组rank,在合并时只需要比较深度的大小即可。
初始化函数如下

void init(int n)
{
    for (int i = 1; i <= n; ++i)
    {
        fa[i] = i;
        rank[i] = 1;
    }
}

合并代码

void merge(int i, int j)
{
    int x = findx(i), y = findx(j); 
    if (rank[x] <= rank[y])
        fa[x] = y;
    else
        fa[y] = x;
    if (rank[x] == rank[y] && x!=y)
        rank[y]++;  //如果深度相同且根节点不同,则新的根节点的深度+1
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_春与修罗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值