代码随想录算法训练营 Day47 | 图论 part05

并查集(Union-Find)理论基础

1. 基本概念

并查集是一种用于处理集合合并与查询的数据结构,主要支持两种操作:

  • Find(查找):判断某个元素属于哪个集合(找到根节点)
  • Union(合并):将两个集合合并成一个集合

常用于解决:

连通性问题(是否在同一集合)

2. 核心思想

用一个数组 parent 表示每个节点的"父节点",形成一棵树结构:

  • 每个集合有一个根节点(代表元)
  • 判断两个元素是否属于同一集合:
    👉 看它们的根节点是否相同

3. 基本操作

(1)初始化
复制代码
for(int i = 0; i < n; i++){
  parent[i] = i; // 每个节点的父节点是自己
}
(2)查找(Find)
复制代码
int find(int x){
  if(parent[x] != x){
    parent[x] = find(parent[x]); // 路径压缩
  }
  return parent[x];
}

作用:

  • 找到集合的根节点
  • 顺便进行路径压缩(优化)
(3)合并(Union)
复制代码
void unite(int x, int y){
  int rootX = find(x);
  int rootY = find(y);

  if(rootX != rootY){
    parent[rootY] = rootX; // 合并
  }
}

4. 优化技巧

(1)路径压缩

find 过程中,把所有节点直接挂到根节点上:

复制代码
parent[x] = find(parent[x]);

作用:

  • 降低树高度
  • 加快后续查询
(2)按秩合并(或按大小合并)
复制代码
if(rank[rootX] < rank[rootY]){
  parent[rootX] = rootY;
} else {
  parent[rootY] = rootX;
}

作用:

  • 保持树尽量平衡
  • 避免退化成链表

5. 时间复杂度

在路径压缩 + 按秩合并优化下:

  • 单次操作复杂度:接近 O(1)
  • 精确为:O(α(n))(反阿克曼函数,极慢增长)

可以认为是常数时间

6. 适用场景

并查集常用于:

  • 连通性判断(两个点是否连通)
  • 图的连通分量统计
  • 最小生成树(Kruskal)
  • 岛屿问题(动态合并)
  • 网络连接问题

107. 寻找存在的路线

题目描述

给定一个包含 n 个节点的无向图中,节点编号从 1 到 n (含 1 和 n )。

你的任务是判断是否有一条从节点 source 出发到节点 destination 的路径存在。

输入描述

第一行包含两个正整数 N 和 M,N 代表节点的个数,M 代表边的个数。

后续 M 行,每行两个正整数 s 和 t,代表从节点 s 与节点 t 之间有一条边。

最后一行包含两个正整数,代表起始节点 source 和目标节点 destination。

输出描述

输出一个整数,代表是否存在从节点 source 到节点 destination 的路径。如果存在,输出 1;否则,输出 0。

输入示例

复制代码
5 4
1 2
1 3
2 4
3 4
1 4

输出示例

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

int n, m;
// father[i] 表示节点 i 的父节点
vector<int> father(101, -1);
// 初始化:每个节点的父节点都是自己
void init() {
    for (int i = 1; i <= n; i++) {
        father[i] = i;
    }
}
// 查找根节点(带路径压缩)
int find(int u) {
    // 如果不是根节点,就递归查找,并压缩路径
    return u == father[u] ? u : father[u] = find(father[u]);
}
// 合并两个集合
void join(int u, int v) {
    u = find(u);
    v = find(v);

    // 如果已经在同一集合,不需要合并
    if (u == v) return;

    // 将 v 的根挂到 u 上
    father[v] = u;
}
// 判断两个节点是否属于同一集合
bool issame(int u, int v) {
    u = find(u);
    v = find(v);
    return u == v;
}

int main() {
    cin >> n >> m;
    // 初始化并查集
    init();
    // 读入边并进行合并
    for (int i = 0; i < m; i++) {
        int s, t;
        cin >> s >> t;
        join(s, t);
    }
    int start, end;
    cin >> start >> end;
    // 判断 start 和 end 是否连通
    cout << issame(start, end) << endl;
    return 0;
}

总结

1. 核心思路

用并查集维护连通关系:

  • join(s, t):表示 s 和 t 连通
  • 最后判断 startend 是否在同一集合

本质是:

判断两个节点是否连通

2. 关键操作
  • find(u):查找根节点(带路径压缩)
  • join(u, v):合并两个集合
  • issame(u, v):判断是否在同一集合
3. 优化点

路径压缩:

复制代码
father[u] = find(father[u]);

作用:

  • 降低树高度
  • 提高查询效率
4. 复杂度
  • 单次操作:接近 O(1)
  • 总体复杂度:O(n + m)
相关推荐
爱睡懒觉的焦糖玛奇朵4 小时前
【从视频到数据集:焦糖玛奇朵的魔法工具使用说明】
人工智能·python·深度学习·学习·算法·yolo·音视频
Runawayliquor4 小时前
opbase:CANN 所有算子的公共地基
大数据·数据库·人工智能·算法
徐安安ye4 小时前
FlashAttention 为什么对序列长度这么“敏感”?
人工智能·算法
黎阳之光6 小时前
黎阳之光:以视频孪生重构智能监盘,为燃机打造新一代智慧电厂大脑
大数据·人工智能·算法·安全·数字孪生
绝知此事6 小时前
【算法突围 02】树形结构与数据库索引:树形结构与数据库索引:从 BST 到 B+ 树的演化与 MySQL 优化
数据库·mysql·算法·面试·b+树
清木!7 小时前
排序算法比较
数据结构·算法·排序算法
吴可可1237 小时前
用Teigha修改并保存CAD文件
数据库·算法·c#
灰灰勇闯IT8 小时前
ops-reduce:ReduceMax 与 ReduceMean 的并行优化
算法
水木流年追梦9 小时前
大模型入门-Reward 奖励模型训练
开发语言·python·算法·leetcode·正则表达式
沙威玛_LHE9 小时前
P13376题解
算法