C++ 实现带路径压缩的并查集算法优化思路详解方案及其判定逻辑源码完整实现【源码】

夜强君_6023

夜强君_6023

2026-05-21

571人浏览

原创

路径压缩需递归返回时自底向上更新父指针,仅一次递归不赋值会导致中间节点未压缩;union前必须判连通以避免冗余操作和破坏按秩合并;路径压缩与按秩合并可共存,rank仅作合并决策上界,不随压缩更新。

c++ 实现带路径压缩的并查集算法优化思路详解方案及其判定逻辑源码完整实现【源码】

为什么路径压缩不能只靠递归一次就完事

路径压缩的核心目标是让查找过程中经过的所有节点直接指向根节点,而不是仅仅把查询节点连到根上。如果只做一次 find(x) 递归后简单赋值 parent[x] = find(parent[x]),但没在返回前更新当前层的 parent[x],就会漏掉中间节点——尤其在多层嵌套时,只有最深那一层被压,上面几层仍维持旧链。

正确做法是在递归返回时「自底向上」重连:先拿到根,再把当前节点的父指针设为该根。这样整条路径上的每个节点都会在各自函数栈帧中完成跳转。

  • 错误写法:return parent[x] == x ? x : find(parent[x]);(没更新 parent[x])
  • 正确写法:return parent[x] = (parent[x] == x ? x : find(parent[x]));
  • 注意:必须用赋值表达式参与 return,否则 parent[x] 不会被修改

union 操作里要不要检查是否已连通

不做检查也能工作,但会徒增一次不必要的 find 调用和潜在的父指针修改开销。更关键的是,如果后续依赖「合并次数」或「连通分量数」统计,未判重会导致计数错误。

标准实现中,unionSets(a, b) 应该先 find(a) 和 find(b) 得到根,再比对是否相等。相等就直接返回,不执行任何指针操作。

  • 避免冗余操作:两次 find + 一次比较,远快于一次 find + 一次赋值 + 可能触发的树高更新
  • 影响按秩合并:若跳过判等,可能把小树挂到大树下,破坏秩平衡,使后续 find 平均变慢
  • 典型错误:写成 parent[find(a)] = find(b); 而不先判断,导致同一集合内反复合并

按秩合并(union by rank)和路径压缩能否共存

可以,而且应该共存。路径压缩优化查找时间,按秩合并控制树高增长,二者解决不同维度的问题,叠加后并查集的单次操作均摊时间复杂度可达 O(α(n))(阿克曼反函数,实际中 ≤ 4)。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

但要注意:路径压缩会改变节点深度,所以「秩(rank)」不再表示真实高度,而是一个上界估计值。因此 rank 数组只在合并时用于决策谁当父节点,不参与查找逻辑。

  • rank[i] 初始全为 0;每次合并两个同秩根时,被选为子树的那个根对应 rank 不变,父节点的 rank 加 1
  • 路径压缩不修改任何 rank 值,哪怕某个节点被压缩后实际深度变成 1,它的 rank 还是原来那个上界
  • 误用风险:有人试图在路径压缩中同步更新 rank,这不仅无意义,还会破坏按秩合并的语义

C++ 完整实现中容易被忽略的细节

完整可运行代码的关键不在算法主干,而在初始化、边界处理和类型安全。比如数组索引从 0 还是 1 开始、rank 和 parent 是否用 vector 动态分配、是否支持负数索引等,都会影响实操稳定性。

以下是最简但健壮的实现要点:

  • 用 vector<int> parent, rank;</int>,下标 0 ~ n-1 对应节点 0 ~ n-1,避免偏移计算出错
  • 构造函数中显式调用 iota(parent.begin(), parent.end(), 0); 初始化,别手写循环漏掉某处
  • find 必须声明为 const 不可行——因为要改 parent[x],所以成员函数不能加 const
  • 如果节点编号不连续(如 ID 是字符串或大整数),得换哈希表实现,此时路径压缩依然有效,但 rank 维护成本上升,通常改用 size 合并更稳妥

真正难的不是写出 find 和 unionSets,而是确保初始化没越界、合并时没把无效索引传进去、以及在多线程场景下意识到它默认不安全——这些地方不出错,算法才真的算“可用”。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2248

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1019

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

327

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

406

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

580

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1409

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1217

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习