并查集学习笔记
并查集
什么是并查集
并查集是一种树形的数据结构,可以处理不相交集合之间的查询和合并的问题。
如何实现
每个集合用一棵树来表示,树的根节点的编号就是整个集合的编号,每个节点存放其父节点的下标,下标和其指示的父节点相等时表明该节点是根节点。
基本并查集的代码实现
#include <iostream>
#include <cstdio>
const int MAXN = 10001; //并查集中的最大元素个数
using namespace std;
int pre[MAXN]; //用数组存放并查集, 其中pre[i]存放的是i的父节点的下标
void init_set() {
for(int i = 1; i < MAXN; ++i)
pre[i] = i; //初始化每个节点都是一个父节点
}
int find_set(int x) {
if(x == pre[x]) return x; //父节点是它本身, 则x为该树的根节点
return find_set(pre[x]); //通过递归来查询根节点
}
void union_set(int a, int b) {
int x = find_set(a);
int y = find_set(b);
if(x == y) return; //两个元素属于同一个集合, 不需要合并
pre[x] = y; //pre[y] = x;也可,将其中一个树的根节点嫁接到另一棵树上即可
}
上面的代码已经能实现并查集的所有基本操作了,其仍然有优化的空间。
查找优化
如果一棵树上的每个节点都只有一个子节点和父节点,假设这棵树高为n,则每次查询树上的子节点的根节点时都需要对其到根节点之间的所有元素进行一次遍历,而这种遍历实际上是为所谓的,我们如果能把每一个子节点的直接父节点改为根节点,则查询的时间复杂度可以降为O(1)。
int find_set(int x) {
if(x == pre[x]) return x;
return pre[x] = find_set(pre[x]); //在回溯时修改每个节点的父节点,第一次查询时的时间复杂度不会发生变化,第一次以后复杂度降为O(1)
}
合并优化
在合并两棵高度不同的树时,如果将高度较高的树嫁接到较低的树上,这样在查询某些节点(高树上的节点)时会产生不必要的负担,我们可以通过维护一个高度数组来保证将较低的树嫁接到高的树上,这样树的总高度不会发生变化,查询的时间也最优。
int height[MAXN];
memset(height, 0, sizeof(height));
void union_set(int a, int b) {
int x = find_set(a);
int y = find_set(b);
if(x == y) return;
if(height[x] < height[y]) {
pre[x] = y;
}
if(height[x] == height[y]) { //当两棵树的高度相同时,随便将一棵树嫁接到另一棵上
height[y]++;
height[x] = y;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人