hyx0411

导航

C语言数据结构——并查集

C语言数据结构——并查集

一、什么是并查集

并查集,英文简称 DSU(Disjoint Set Union,不相交集合合并),是一种处理元素分组、集合合并、连通性判断的高效数据结构。

它专门解决三类核心问题:

  1. 合并:将两个独立的集合合并为一个集合;

  2. 查找:查询某个元素所属集合的根节点;

  3. 判连通:判断两个元素是否属于同一个集合(是否连通)。

通俗理解:
我们可以把每个集合看作一个家族,每个元素是家族成员。

• 初始化:每个人自成一个家族,自己是自己的族长;

• 合并:两个家族联姻,合并成一个大家族;

• 查找:找到当前成员的最终族长;

• 判连通:两个人是否属于同一个家族。

并查集最大的优势:代码极简、时间复杂度极低,是OJ刷题、图论连通性问题的必备模板。

二、并查集核心原理

并查集通过一个数组parent[] 实现映射关系:

• parent[x]:表示元素x的父节点;

• 若 parent[x] == x,说明x是根节点(族长),代表一个集合;

• 所有根节点相同的元素,属于同一个集合。

三、三大基础操作

1. 初始化操作 init

初始状态下,每个元素独立成集合,自己的父节点是自己。

代码实现

#define MAXN 1005
int parent[MAXN];
// 初始化并查集:1~n 所有元素自成一派
void init(int n) {
    for (int i = 1;<= n; i++) {
        parent[i] = i;
    }
}

2. 查找操作 find

从当前元素向上递归/循环查找,直到找到根节点(parent[x] = x)。

递归版(简单直观)

// 查找x的根节点
int find(int x) {
    // 找到根节点,直接返回
    if (parent[x] == x) {
        return x;
    }
    // 递归向上找父节点
    return find(parent[x]);
}

循环版(避免递归栈溢出)

int find(int x) {
    while (parent[x] != x) {
        x = parent[x];
    }
    return x;
}

3. 合并操作 unionSet

先找到两个元素的根节点,若根节点不同,将其中一个根节点的父节点指向另一个根节点,完成集合合并。
注意:union是C语言关键字,不能用作函数名,统一用unionSet
代码实现

// 合并x和y所在的集合
void unionSet(int x, int y) {
    int fx = find(x);  // x的根节点
    int fy = find(y);  // y的根节点
    
    // 不属于同一集合,才合并
    if (fx != fy) {
        parent[fx] = fy;
    }
}

4. 拓展:连通性判断

基于查找操作,判断两个元素是否同根,即可判断是否连通:

// 判断x、y是否在同一集合
int isConnect(int x, int y) {
    return find(x) == find(y);
}

四、并查集两大核心优化

无优化的并查集在最坏情况下会退化成单链树(例如 1→2→3→4→5),查找时间复杂度会变成 O(n)。

为了极致效率,引入两个经典优化,优化后时间复杂度接近 O(1)(反阿克曼函数,可视为常数)。

优化1:路径压缩(最常用、必加)

原理

在查找根节点的过程中,把路径上所有节点的父节点直接指向根节点,让树的层数变为2层,后续查找直接一步到位。

路径压缩版 find(递归终极版)

int find(int x) {
    if (parent[x] != x) {
        // 递归找根,并回溯修改父节点为根节点
        parent[x] = find(parent[x]);
    }
    return parent[x];
}

通俗解释

原本路径:3→2→1(根)
路径压缩后:3→1、2→1,下次查找3、2可直接找到根1。

优化2:按秩合并(进阶优化)

路径压缩后基本够用,但为了绝对平衡,可搭配按秩合并。

• 新增数组rank[],记录每个根节点对应树的深度;

• 合并时:浅树合并到深树,避免树过高。

完整带秩初始化+合并

#define MAXN 1005
int parent[MAXN];
int rank_[MAXN];  // rank是关键字,加下划线区分

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

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

// 按秩合并
void unionSet(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if (fx == fy) return;

    // 浅树挂到深树下面
    if (rank< rank_[fy]) {
        parent[fx] = fy;
    } else {
        parent[fy] = fx;
        // 深度相同时,新根深度+1
        if (rank_[fx] == rank_[fy]) {
            rank_[fx]++;
        }
    }
}

五、C语言并查集模板

精简、高效、适配所有基础连通性题目:

#include <stdio.h>
#define MAXN 1005

int parent[MAXN];

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

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

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

// 判断连通
int isConnect(int x, int y) {
    return find(x) == find(y);
}

int main() {

    return 0;
}

六、实战例题

题目描述

给定5个元素,初始各自独立:

  1. 合并 1、2

  2. 合并 2、3

  3. 判断 1、3 是否连通

  4. 判断 1、4 是否连通

完整解题代码

#define MAXN 10

int parent[MAXN];

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

int find(int x) {
    if (parent[x] != x)
        parent[x] = find(parent[x]);
    return parent[x];
}

void unionSet(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx != fy) parent[fx] = fy;
}

int main() {
    init(5);    // 初始化5个元素
    unionSet(1, 2);
    unionSet(2, 3);

    // 连通性判断
    if (isConnect(1, 3)) printf("1和3连通\n");
    else printf("1和3不连通\n");

    if (isConnect(1, 4)) printf("1和4连通\n");
    else printf("1和4不连通\n");

    return 0;
}

运行结果

1和3连通
1和4不连通

七、并查集经典适用场景

  1. 图论连通块统计:统计一张图中有多少个独立连通块;

  2. 关系归类问题:朋友关系、亲戚关系、组队分组;

  3. 最小生成树:克鲁斯卡尔(Kruskal)算法核心依赖并查集判环;

  4. 动态连通性问题:不断加边、不断查询连通状态。

八、总结

  1. 并查集三核心:初始化、查找、合并;

  2. 路径压缩是必学优化,时间复杂度趋近常数级;

  3. 代码极简、通用性极强,是算法竞赛、期末刷题的万能模板;

  4. 核心思想:同根连通、异根独立,合并根节点、压缩查找路径。

posted on 2026-05-03 20:09  芸歆  阅读(65)  评论(1)    收藏  举报