并查集两优化——按秩合并与路径压缩

1、未优化

1、p[x]表示x的父节点是谁。 初始化时,将其父节点初始化为他本身,即p[x] = x

2、当要合并两个集合时,可以将每一个集合看成是一棵树,每棵树至少存在一个根节点(即本身),当合并两个不相同的集合时,一棵树会成为另一颗树的子树(儿子)。

3、合并x所在集合与y所在集合的方法是找到x的祖宗节点和y的祖宗节点,然后让x的祖宗节点成为y的祖宗节点的儿子节点。

4、找到一个x的祖宗节点的方法是,不断递归x的父节点p[x],直到x=p[x],则说明,此时p[x]就是原x的祖宗节点了,返回p[x]即可。
注意:若数据太大或者太***钻可以改用循环迭代来寻找,本文暂不提及。

↓ 未优化前,裸的并查集模板 ↓

复制
int p[N]; // p[x] 表示 x 的父节点是谁 int get ( int x ) { if ( x == p[x] ) return x; // 因为这里 x 已经等于 p[x] 了,所以返回x或p[x]都可以 return get ( p[x] ); } void marge ( int x, int y ) { x = get ( x ), y = get ( y ); p[x] = y; // 将 子树x 连到 根y 的下面 }

请不要使用未优化的并查集模板,这里写出来只是为了对理解有帮助


2、优化版

下面对两种操作进行优化

优化一:优化查找(get)

查找的优化是路径压缩,大大提高了优化效率

我们可以看到,我们每次get一个x,它都会遍历它的父节点,若我们重复get,则他会重复遍历,这大大降低了效率。

如果我们可以在他返回的时候将他路径上的每个节点父节点全部改为根节点,则下一次查找时,可不用再次逐一查询。
想实现这个方式只需让p[x]等于返回来的根节点的值:p[x] = get ( p[x] )

优化后的get函数如下:

复制
int get ( int x ) { if ( x == p[x] ) return x; return p[x] = get ( p[x] ); }

优化二:优化合并(marge)

合并的优化方式是按秩合并,这种优化可以忽略,不去使用它。 在数据量非常大,且数据***钻时,可考虑加上这个优化,否则,优化一 足矣

1、优化方法是创建一个h[]数组维护每个集合树的深度

2、在marge时,将深度小的树作为深度大的的儿子, 最后树的总深度仍是最大的那个深度,这样,在find时,会提高效率。

3、若两颗树的深度相同,则谁做谁的儿子都可以,只需将其深度加一即可

最终的全优代码如下:
(再次说明:按秩合并在竞赛中基本是用不到的。无需优化)

复制
int p[N], h[N]; int get ( int x ) { if ( x == p[x] ) return x; return p[x] = get ( p[x] ); } void marge ( int x, int y ) { x = get ( x ), y = get ( y ); if ( h[x] == h[y] ) { p[x] = y; h[y] += 1; } else if ( h[x] < h[y] ) { p[x] = y; } else { p[y] = x; } }
posted @   Jude_Zhang  阅读(1082)  评论(3编辑  收藏  举报
编辑推荐:
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
阅读排行:
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· Vite CVE-2025-30208 安全漏洞
· 《HelloGitHub》第 108 期
· MQ 如何保证数据一致性?
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
点击右上角即可分享
微信分享提示