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. 输入多组关系,统计最终有多少个独立连通块
相关推荐
To_OC13 小时前
LC 15 三数之和:双指针不难,难的是把去重做对
javascript·算法·leetcode
阿维的博客日记15 小时前
MultipartFile 是不是表示仅仅是一个分片?
java·后端·spring·multipartfile
renhongxia115 小时前
世界模型,是“空中楼阁”还是AGI的“最后一块拼图”?
运维·服务器·数据库·人工智能·算法·agi
程序员无隅16 小时前
Coding Agent 为什么压缩上下文后还能继续工作?上下文模块设计拆解
java·开发语言·数据库
Python+9916 小时前
Java 枚举类(Enum)详解:从基础到高级应用
java·开发语言·python
二炮手亮子16 小时前
浅记java线程池
java·开发语言
一路向北North16 小时前
Spring Security OAuth2.0(23):分布式系统授权-转发明文给微服务
java·spring·微服务
zmzb010317 小时前
C++课后习题训练记录Day157
开发语言·c++
zephyr0518 小时前
动态规划-最长上升子序列问题
算法·动态规划
闪电悠米18 小时前
力扣hot100-56.合并区间-排序详解
数据结构·算法·leetcode·贪心算法·排序算法