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. 输入多组关系,统计最终有多少个独立连通块
相关推荐
间歇性努力持续性发呆的野生快乐选手9 分钟前
dfs回溯,bfs枚举,完全背包
c++·算法·深度优先·宽度优先
郝学胜_神的一滴35 分钟前
干货版《算法导论》17:双数极值配对与卡牌手牌编码最优解
数据结构·算法
码工许师傅1 小时前
一文读懂《Effective C++ 第三版》的55条黄金法则
c++
萧瑟余晖1 小时前
Java深入解析篇十八之响应式编程
java·开发语言
有点。1 小时前
C++深度优先搜索(三)
开发语言·c++·深度优先
nike0good1 小时前
Codeforces Round 1101 (Div. 2) 题解
算法
中年阿甘1 小时前
解析式布局-二次线长布局
线性代数·算法·矩阵
程序喵大人1 小时前
【C++进阶】STL算法与函数对象 -【C++进阶】STL算法与函数对象
开发语言·c++·算法
IKUN家族1 小时前
Spring MVC(五)
java·spring·mvc
我不会插花弄玉2 小时前
10.list【由浅入深-C++】
数据结构·c++·list