学习笔记 - 并查集
本人实力不济,如有错误或建议及补充,请指出
1.定义
并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。
顾名思义,并查集支持两种操作:
- 合并(Union):合并两个元素所属集合(合并对应的树)
- 查询(Find):查询某个元素所属集合(查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合
并查集在经过修改后可以支持单个元素的删除、移动。
(注:这两段文字均源于OI wiki
2.实现
我们首先设置一个数组fa代表i的父亲是fa[i]
2.0 初始化
我们假设每个节点的父亲刚开始都是自己,即:
int fa[N]; void init(){ for(int i=1;i<=n;i++) fa[i]=i; }
2.1 查询自己的祖先(find函数的实现)
2.1.1 朴素实现
顾名思义,X先查询自己的父亲Y,Y再查询自己的父亲是Z……直到最高的一辈,即F查询到自己的父亲是F。
此时F就是X的祖先。
int find(int x) { if(fa[x]!=x) return find(fa[x]);//不是祖先,找它的父亲 else return x;//找到了祖先,返回 }
2.1.2 路径压缩
但考虑极端情况,朴素算法的并查集构成的树是一条链式的,时间复杂度是O(n)。
再回归定义,我们只需要该树的根节点就够了,所以此时可以考虑路径压缩
我们可以把每个结点直接连接到根节点。
代码实现:
int find(int x) { if(fa[x]!=x) return fa[x]=find(fa[x]);//去找祖先,将找到的祖先设为自己的父亲(辈分乱了啊喂) else return x; }
除了第一次查询时间复杂度为O(n),后续几次查询均为O(1)
(谁家好人费怎么大劲造个并查集结果只查询一次)
2.2 合并集合(Union函数)
为什么不将函数名取为union呢,因为union是C++中的联合体(一种关键字就是了)。
由于路径压缩已经介绍了,这里就不提供朴素实现了
void find(int x,int y) { int fax=find(x),fay=find(y);//查询X,Y的祖先 fa[fay]=fax;//将Y的祖先的父亲设为X的祖先 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)