当前位置: 首页 > news >正文

【数据结构】并查集:从入门到精通

目录

  • 并查集的基本概念
  • 查找操作(Find)
    • 基本查找
    • 路径压缩优化
  • 合并操作(Union)
    • 基本合并
    • 按秩合并
      • 按高度合并
      • 按节点数量合并
    • 总结对比
  • 例题训练
    • P3367 【模板】并查集
  • 总结

引言:
在编程竞赛中,我们常常需要处理元素分组与集合操作的问题。并查集(Union-Find)作为一种高效的数据结构,能够高效便捷地实现集合的“合并”与“查找”操作,本篇文章将详细介绍并查集的原理和用途。

并查集的基本概念

并查集是一种树形的数据结构,主要支持**合并(Union)查找(Find)**两种操作:

  • 合并:将两个不相交的子集合合并成一个统一的集合(合并相应的根节点)。
  • 查找:查询元素所属的集合(找根节点)。

父节点数组 fa[]

  • 作用fa[x] 存储节点 x 的父节点。
  • 初始化:每个节点初始时是独立集合,指向自身。
for (int i = 1; i <= n; i++)fa[i] = i

例如,初始状态下 fa[1] = 1fa[2] = 2 等,每个节点自成一个集合。

查找操作(Find)

基本查找

查找的目标是找到元素所在集合的根节点,过程如下:

int Find(int x) {if (fa[x] == x) return x;  // 父节点是自身,找到根return Find(fa[x]);        // 递归查找父节点的根
}

路径压缩优化

为了加速后续查找,可在查找时压缩路径,让路径上的节点直接指向根:

int Find(int x) {if (fa[x] == x) return x;  return fa[x] = Find(fa[x]);  // 递归查找并直接指向根
}

合并操作(Union)

基本合并

将两个集合合并,做法是把一个集合的根指向另一个集合的根:

void Union(int x, int y) {fa[Find(x)] = Find(y);  // x 所在集合的根指向 y 所在集合的根
}

按秩合并

为避免合并后树过高影响效率,可按集合大小(或深度)合并,把小集合的根指向大集合的根。

按高度合并

1. 核心思想

合并时,让较矮树的根指向较高树的根
若两棵树高度相同,合并后新树高度会 +1 。
这样能保证树的高度尽可能小,让 find 操作(查找根)更快。

2. 关键变量

  • h[] 数组:h[root] 存储以 root 为根的树的高度
  • fa[] 数组:存储节点的父节点。

3. 代码展示

void Union(int x, int y){int rootx = Find(x);  // 找到 x 所在集合的根int rooty = Find(y);  // 找到 y 所在集合的根if(rootx != rooty)   // 不在同一集合才合并{   if(h[rootx] < h[rooty]) //x 所在树更矮 → 让 x 的根指向 y 的根 fa[rootx] = rooty;  else if(h[rootx] > h[rooty])// y 所在树更矮 → 让 y 的根指向 x 的根fa[rooty] = rootx;  else// 两棵树高度相同 → 随便选一个{fa[rootx] = rooty;  h[rooty]++;  // 合并后,新树高度 +1 }}
}

合并后树的高度被严格控制,find 操作的时间会更稳定,接近 O(α(n))O(α(n))O(α(n))(阿克曼函数反函数,极高效 )。

按节点数量合并

1. 核心思想

合并时,让较小集合的根指向较大集合的根。这样能保证大集合的树尽可能“粗壮”,小集合合并进来不显著增加树的高度,间接让 find 更快。

2. 关键变量

  • s[] 数组:s[root] 存储以 root 为根的集合的节点总数(初始时每个节点自身为集合,s[i]=1 )。
  • fa[] 数组:存储节点父节点。

3. 代码展示

void Union(int x, int y){int rootx = Find(x);  // 找 x 的根int rooty = Find(y);  // 找 y 的根if(rootx != rooty)// 不同集合才合并{   if(s[rootx] <= s[rooty])// x 集合更小(或相等)→ 让 x 的根指向 y 的根{  p[rootx] = rooty;  s[rooty] += s[rootx];  // y 集合大小 += x 集合大小 }else// y 集合更小 → 让 y 的根指向 x 的根{p[rooty] = rootx;  s[rootx] += s[rooty];  // x 集合大小 += y 集合大小 }}
}

总结对比

对比项按高度合并按节点数量合并
核心优化点控制树的高度,避免合并后树过高控制集合大小,让小集合合并进大集合
关键数组h[] 存树高,fa[] 存父节点s[] 存集合大小,fa[] 存父节点
适用场景对“树高度敏感”,或需严格限制树高需频繁查“集合大小”,或追求“通用高效”
实际效率接近 O(α(n))O(α(n))O(α(n)) ,树高控制更直接接近 O(α(n))O(α(n))O(α(n)) ,额外支持“集合大小查询”

例题训练

来一个模板题练练手:

P3367 【模板】并查集

题目来源

AC代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int N=2e5+6;
int n,m,f[N],z,x,y,h[N];
int Find(int x)
{if(f[x]==x)return x;else return Find(f[x]);
}
void Union(int x,int y)
{int rx=Find(x);int ry=Find(y);if(rx!=ry){if(h[rx]<h[ry])f[rx]=ry;else if(h[rx]>h[ry])f[ry]=rx;else{f[rx]=ry;h[ry]++;}}
} 
void solve()
{cin>>n>>m;for(int i=1;i<=n;i++)f[i]=i,h[i]=1;while(m--){cin>>z>>x>>y;if(z==1)Union(x,y);else if(z==2){int tx=Find(x);int ty=Find(y);if(tx==ty)cout<<"Y"<<endl;elsecout<<"N"<<endl;}}
}
signed main()
{IOS;int _=1;
//	cin>>_;while(_--)solve();return 0;
}

总结

并查集通过 find(含路径压缩)和 union(含按秩合并)操作,高效处理动态集合的合并与查找,时间复杂度近似 O(α(n))O(α(n))O(α(n))(阿克曼函数反函数,极接近常数 ),广泛应用于连通性问题。掌握其原理与优化,能轻松应对各类集合操作问题 。

http://www.lryc.cn/news/618465.html

相关文章:

  • nextTick和setTimeout的区别
  • 卓伊凡谈AI编程:历史、现状与未来展望-以前面向搜索引擎现在面向AI机器人-优雅草卓伊凡
  • IMU量程介绍
  • 悬空标记攻击 -- idekctf 2025 CTFinder
  • [激光原理与应用-255]:理论 - 几何光学 - CCD成像过程
  • 2025牛客暑期多校训练营3(FDJAEHB)
  • 3.8 vue2 devServer配置和 CDN 加载外部资源
  • JavaScript 实现模块懒加载的几种方式
  • Flink Redis维表:Broadcast Join与Lookup Join对比及SQL示例
  • nvm install 14.21.3 时npm 无法下载和识别
  • code-inspector-plugin插件
  • npm、pnpm、yarn区别
  • 【Linux系统】详解Ext2,文件系统
  • RabbitMQ-知识技能图谱(总结篇)
  • 智能家居Agent:物联网设备的统一控制与管理
  • 算法打卡力扣第88题:合并两个有序数组(easy)
  • 第五章 树与二叉树
  • 虚拟机高级玩法-网页也能运行虚拟机——WebAssembly
  • Day24|学习前端CSS
  • AI入门学习--AI模型评测
  • Java集合学习之forEach()遍历方法的底层原理
  • 深度解读 WizTelemetry 2.0:链路追踪如何让分布式系统“无所遁形”
  • 【2025最新版】Java基础知识学习路线图:从入门到精通的系统化指南
  • 深度贴:前端网络基础及进阶(2)
  • 【网络运维】Linux和自动化: Ansible基础实践
  • 【接口自动化】-11-接口加密签名 全局设置封装
  • 回归预测 | Matlab实现CNN-BiLSTM-self-Attention多变量回归预测
  • 如何使用gpt进行模型微调?
  • iceberg FlinkSQL 特性
  • 古风修仙主题登录页面设计与实现 附源码 ~~~