并查集
第一步先初始化
| int f[N]; |
| inline void init(int n) |
| { |
| for(int i=1;i<=n;i++) |
| fa[i]=i; |
| } |
假如有编号1,2,3,...,n,n个元素,我们用一个数组fa[]来储存每个元素的父节点(因为每个元素有且只有一个父节点,所以这是可行的),一开始都将父节点设为自己
第二步查询
| int find(int x) |
| { |
| if(fa[x]==x) |
| return x; |
| else |
| return find(fa[x]); |
| } |
使用递归的写法实现对代表元素的查询:一层一层的访问父节点,直至根节点(根节点的标志就是父节点是本身)。要判断两个元素是否属于同一个集合,只需要看他们的根节点是否相同即可
第三步合并
| inline void merge(int i,int j) |
| { |
| fa[find(i)]=find(j); |
| } |
先找到两个集合的代表元素,然后将前者的父节点设为后者即可,当然也可以将后者的父节点设为前者
- 进阶版,路径压缩
在每次查询时,把沿途的每个节点的父节点都设为根节点即可。在下次查询时就可以省事
!!!注意:只有在每次查找时才进行路径压缩,因此初始化和合并的部分代码都相同
| |
| int find (int x) |
| { |
| if(x==fa[x]) |
| return x; |
| else { |
| fa[x]=find (fa[x]); |
| return fa[x]; |
| } |
| } |
| |
| int find (int x) |
| { |
| return x==f[a]?x:(fa[x]=find(fa[x])); |
| } |
- 进阶版 按秩合并
按秩合并的原理就是应该把结构简单的树往结构复杂的树上合并,而不是相反,因为这样合并后到根节点距离变长的节点个数比较少
开一个rank[]数组记录每个根节点对应的树的深度(如果不是根节点,其 rank相当于它作为根节点的子树的深度)。一开始,把所有元素的rank(秩)设为1。合并时比较两个根节点,把rank较小者往rank较大者合并。
(注意:路径压缩和按秩合并如果一起使用,时间复杂度接近O(n),但可能会破坏rank的准确性)
初始化(按秩合并)
| inline void init(int n) |
| { |
| for(int i=1;i<=n;i++) |
| { |
| fa[i]=i; |
| rank[i]=1; |
| } |
| } |
合并
| inline void merge(int i,int j) |
| { |
| int x=find(i),y=find(j); |
| if(rank[x]<=rank[y]) |
| fa[x]=y; |
| else |
| fa[y]=x; |
| if(rank[x]==rank[y]&&x!=y) |
| rank[y]++; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理