C++并查集:高效解决连通性问题

一、前言

C++ 语法、面向对象、STL 已经全部收官。从今天开始,正式进入高阶数据结构与算法深耕 。首篇先学并查集:结构简单、代码短、考点极多、适用场景非常广。

二、并查集是什么

并查集(Disjoint Set Union,DSU)三个核心操作:

  1. 合并:把两个集合合并成一个
  2. 查找:找某个元素的根节点
  3. 判连通:判断两个元素是否在同一个集合

形象理解:每个人是一个节点,认识的人归为一个圈子 ,并查集就是用来管理圈子、合并圈子、查是否同圈。

三、并查集核心思想

  • 每个节点有一个父节点 parent \[\]
  • 根节点:自己的父节点是自己
  • 找祖先:一路往上找,直到父节点等于自身
  • 合并集合:把一个集合的根,挂到另一个集合根下面

四、基础朴素版并查集

1. 初始化

每个人初始自己是一个集合,父节点等于自己

复制代码
const int N = 1005;
int parent[N];

// 初始化
void init(int n)
{
    for(int i = 1; i <= n; i++)
    {
        parent[i] = i;
    }
}

2. 查找根节点

复制代码
int find(int x)
{
    if(parent[x] == x) 
        return x;
    return find(parent[x]);
}

3. 合并两个集合

复制代码
void unite(int x, int y)
{
    int fx = find(x);
    int fy = find(y);
    if(fx != fy)
    {
        parent[fy] = fx;
    }
}

4. 判断是否连通

复制代码
bool isSame(int x, int y)
{
    return find(x) == find(y);
}

五、优化一:路径压缩(必加)

朴素版查找层数多、效率低。路径压缩:查找时把沿途所有节点直接挂到根节点,下次查找 O (1)。

优化后 find 函数:

复制代码
int find(int x)
{
    if(parent[x] == x)
        return x;
    // 路径压缩:递归回溯直接指向根
    parent[x] = find(parent[x]);
    return parent[x];
}

刷题默认必写路径压缩。

六、优化二:按秩合并(可选)

维护树的高度 / 节点数量,合并时小树挂大树 ,防止树过高。日常刷题只写路径压缩就够用,竞赛再加上按秩合并。

七、并查集完整万能模板(可直接复制刷题)

复制代码
#include <iostream>
using namespace std;

const int N = 1005;
int parent[N];

// 初始化
void init(int n)
{
    for(int i = 1; i <= n; ++i)
        parent[i] = i;
}

// 查找 + 路径压缩
int find(int x)
{
    if(parent[x] != x)
        parent[x] = find(parent[x]);
    return parent[x];
}

// 合并
void unite(int x, int y)
{
    x = find(x);
    y = find(y);
    if(x != y)
        parent[y] = x;
}

// 判断同集合
bool same(int x, int y)
{
    return find(x) == find(y);
}

int main()
{
    int n,m;
    cin >> n >> m;
    init(n);

    while(m--)
    {
        int op,x,y;
        cin >> op >> x >> y;
        if(op == 1)
            unite(x,y);
        else
        {
            if(same(x,y)) cout << "Yes\n";
            else cout << "No\n";
        }
    }
    return 0;
}

八、经典适用场景

  1. 判断图中两点是否连通
  2. 朋友圈、亲戚关系合并
  3. 最小生成树 Kruskal 算法必备
  4. 岛屿数量、连通块统计
  5. 区间合并、分组问题

九、今日核心总结

  1. 并查集三大操作:初始化、查找、合并
  2. 路径压缩是标配优化,极大提升效率
  3. 模板固定,刷题直接套用即可
  4. 常用于连通性判断、集合合并、图论基础题

十、课后练习

  1. 手写并查集模板,实现 5 个元素合并、判断连通
  2. 输入多组关系,统计最终有多少个独立连通块
相关推荐
古法老登瞎折腾12 小时前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
飞Link12 小时前
什么是 AirSim?一文读懂无人机仿真平台
python·算法·无人机
智能运维指南13 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks13 小时前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵13 小时前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设14 小时前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都14 小时前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
xiaoye-duck14 小时前
《C++ 工具库实战》gflags 命令行参数解析库详解
c++·第三方库
鱼宵14 小时前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作
一去不复返的通信er14 小时前
贪心算法-合并区间(LeetCode 56)
算法·leetcode·贪心算法