并查集【算法 12】

news2024/11/15 14:05:39

并查集 (Union-Find) 的基础概念与实现

请添加图片描述

并查集(Union-Find)是一种用于处理不相交集合(disjoint sets)的数据结构,常用于解决连通性问题。典型的应用场景包括动态连通性问题(如网络节点连通性检测)、图论中的最小生成树(Kruskal 算法)、社交网络中的群体归属等。

并查集的两大基本操作
  1. 合并操作 (Union): 将两个不同的集合合并为一个集合。
  2. 查找操作 (Find): 查询某个元素属于哪个集合,通常通过找到该元素所在集合的代表元(根节点)来实现。
并查集的特点

并查集的核心思想是将集合通过树状结构来表示,每个集合有一个根节点,查找某个元素时可以通过追溯其父节点直到找到根节点。合并操作则是将一个集合的根节点连接到另一个集合的根节点。

基础实现

我们可以通过两个数组来实现并查集:

  • parent[] 数组:记录每个元素的父节点。
  • rank[] 数组:记录集合的深度(或称为树的秩)。
#include <stdio.h>

#define MAX 1000  // 假设最大元素数为 1000

int parent[MAX];
int rank[MAX];

// 初始化操作,每个元素自成一个集合
void initialize(int n) {
    for (int i = 0; i < n; i++) {
        parent[i] = i;  // 每个元素的父节点都是自己
        rank[i] = 0;    // 初始时每个集合的秩为 0
    }
}

// 查找操作:查找元素 x 的根节点,并进行路径压缩
int find(int x) {
    if (parent[x] != x) {
        parent[x] = find(parent[x]);  // 递归查找根节点,并进行路径压缩
    }
    return parent[x];
}

// 合并操作:将两个集合合并,按秩优化
void union_sets(int x, int y) {
    int rootX = find(x);
    int rootY = find(y);

    if (rootX != rootY) {
        // 按秩合并:将秩小的树挂在秩大的树上
        if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else {
            parent[rootY] = rootX;
            rank[rootX]++;
        }
    }
}
路径压缩与按秩合并
  • 路径压缩 (Path Compression): 在 find() 操作中,通过递归将查找路径上所有节点直接连接到根节点。这样可以大大减少树的高度,使后续查找更高效。
  • 按秩合并 (Union by Rank): 在合并时,将秩小的树挂到秩大的树上,以减少树的高度,避免退化为链表结构。
时间复杂度分析

并查集的时间复杂度非常接近于常数级别。虽然每次 findunion 的复杂度不是固定的常数,但由于路径压缩和按秩合并的优化,其均摊时间复杂度为 O(α(n)),其中 α(n) 为阿克曼函数的反函数,在实际应用中增长极为缓慢,因此可以视为常数时间。

经典应用:Kruskal 最小生成树算法

Kruskal 算法用于构建无向图的最小生成树,它的核心思想是贪心地选择最小权重的边,前提是该边连接的两个顶点不在同一个集合中,这正好可以用并查集来解决。

示例代码:Kruskal 算法
#include <stdio.h>

#define MAX 1000

typedef struct {
    int u, v, weight;
} Edge;

Edge edges[MAX];
int parent[MAX];
int rank[MAX];
int n, m;  // n 为节点数,m 为边数

void initialize() {
    for (int i = 0; i < n; i++) {
        parent[i] = i;
        rank[i] = 0;
    }
}

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

void union_sets(int x, int y) {
    int rootX = find(x);
    int rootY = find(y);

    if (rootX != rootY) {
        if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else {
            parent[rootY] = rootX;
            rank[rootX]++;
        }
    }
}

int kruskal() {
    int totalWeight = 0;
    int edgeCount = 0;

    initialize();
    
    // 假设 edges[] 按权重从小到大排序
    for (int i = 0; i < m && edgeCount < n - 1; i++) {
        int u = edges[i].u;
        int v = edges[i].v;
        int weight = edges[i].weight;

        if (find(u) != find(v)) {
            union_sets(u, v);
            totalWeight += weight;
            edgeCount++;
        }
    }
    return totalWeight;
}
总结

并查集是一种极为高效的数据结构,特别适用于动态连通性问题。通过路径压缩和按秩合并的优化,保证了其在实际应用中的高效性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2086328.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库sqlite3

数据库 数组、链表、变量 ----->内存&#xff1a;程序运行结束&#xff0c;掉电数据丢失 文件 ----------------------->硬盘&#xff1a;程序运行结束&#xff0c;掉电数据不丢失 数据库&#xff1a;专业存储数据、大量数据 ----->硬盘 常用数据库&#xff1a; …

linux 如何查看cpu核心数量

在Linux系统中&#xff0c;有多种方法可以查看CPU的核心数量。 一、lscpu lscpu命令是最直接的方法之一&#xff0c;它可以显示CPU架构信息&#xff0c;包括CPU数量、每个CPU的核心数、每个核心的线程数等。要查看CPU核心数量&#xff0c;可以直接查看lscpu命令输出的Core(s) …

力扣面试150 删除排序链表中的重复元素 II 哑兵 双指针

Problem: 82. 删除排序链表中的重复元素 II &#x1f468;‍&#x1f3eb; 灵神题解 Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* List…

企业车辆|基于SprinBoot+vue的企业车辆管理系统(源码+数据库+文档)

企业车辆管理系统 基于SprinBootvue的企业车辆管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 后台模块实现 管理员模块实现 驾驶员模块实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主…

悬浮翻译软件有哪些?试试这些利器

在观看外国电影或电视剧的奇幻旅程中&#xff0c;面对字幕如流星般划过屏幕&#xff0c;是否渴望能即时捕捉每一个细微的情感涟漪与幽默火花&#xff0c;让体验更加完整无憾&#xff1f; 此刻&#xff0c;无需再为语言障碍而烦恼&#xff01;悬浮翻译器电脑版作为你贴心的跨文…

新买的笔记本只有一个C盘,进行磁盘分区的操作

开始是这样的: 快捷键 window x 找到磁盘管理 102,400M 100GB 然后右键重命名磁盘名字 最终得到结果如下:

SpringBoot+Vue的AI智能图书馆系统来袭!!

SpringBootVue的AI智能图书馆系统来袭&#xff01;&#xff01; 一、项目介绍用户&#xff08;借阅人&#xff09;图书管理员系统管理员 二、相关技术栈三、项目演示管理员登录用户登录 四、相关地址总结 大家好&#xff0c;这里是程序猿代码之路。在数字化时代的浪潮中&#x…

Python办公自动化 获取文本数据 支持多种类型文件

学好办公自动化,走遍天下都不怕&#xff01;&#xff01; 前面我们已经学习了&#xff0c;如何用python的下载安装以及入门基础知识&#xff0c;并且也知道如何使用python自动处理Excel文件数据、如何批量生成Word文件、如何对数据分析后生成洞察报告、如何用python实现自动发送…

【自由能系列(初级)】自由能原理——神经科学的“能量守恒”方程

【通俗理解】自由能原理——神经科学的“能量守恒”方程 关键词提炼 #自由能原理 #KL散度 #生成模型 #识别密度 #观测数据 #神经科学 第一节&#xff1a;自由能原理的类比与核心概念 1.1 自由能原理的类比 自由能原理在神经科学中的应用&#xff0c;可以类比为一个“大脑的…

Java 面试题:HTTP版本演变--xunznux

文章目录 HTTP版本演变HTTP/0.9HTTP/1.0HTTP/1.1新引入&#xff1a;问题&#xff1a;长连接是什么&#xff1a;管道网络传输&#xff1a;队头阻塞是什么&#xff1f;解决http队头阻塞的方法&#xff1a;HTTP1.1常见性能问题为解决HTTP1.1性能问题而提出的常见优化手段 HTTP/21、…

数据库(专业存储数据)

数组、链表、变量----->内存&#xff1a;程序运行结束&#xff0c;数据丢失 文件-------------->硬盘 数据库&#xff1a;专业存储数据&#xff0c;大量数据----------->硬盘 一、数据库文件与普通文件区别: 1.普通文件对数据管理(增刪改查)效率低 2.数据库对数据…

UNI-APP 打包构建 APK

UNI-APP 打包构建 APK 前言一、WINDOWS&#xff08;在线 - 纯命令版&#xff09;依赖其他前置准备实现原理操作步骤 二、WINDOWS&#xff08;离线 - Android Studio 版&#xff09;依赖&#xff08;首次构建需要联网安装依赖&#xff09;其他前置准备实现原理操作步骤 三、WIND…

【QT】学习笔记:处理数据库 SQLite

在 Qt 中使用 SQLite 数据库非常简单&#xff0c;Qt 提供了 QSqlDatabase 和 QSqlQuery 类来处理数据库的连接、查询、插入、更新和删除等操作。下面是一个示例程序&#xff0c;展示如何在 Qt 中使用 SQLite 数据库。 示例代码 1. 项目配置 首先&#xff0c;确保在项目的 .p…

李宏毅 机器学习与深度学习【2022版】 03

文章目录 一、卷积神经网络CNN二、使用验证集&#xff0c;模型还过拟合的原因三、深度学习的优点四、Spatial Transformer Layer 一、卷积神经网络CNN CNN在影像识别中&#xff0c;表现比较好。 每个感受野 receptive field 都有一个神经元去探测鸟嘴&#xff0c;是没有没要的…

Vue(三)内置指令v-text、html、cloak、once、pre;自定义指令的三种方式、Vue生命周期

文章目录 1. 内置指令1.1 v-text、v-html指令1.2 v-cloak指令1.3 v-once指令1.4 v-pre指令 2. 自定义指令(directives)2.1 函数式2.2 对象式2.3 注意点 3. 生命周期3.1 挂载流程3.2 更新流程3.3 销毁流程 1. 内置指令 1.1 v-text、v-html指令 v-text与v-html都是向所在的节点…

0. Spring 的 控制反转和依赖注入

提起Spring&#xff0c;很多人第一反应就是IOC和AOP。那IOC到底是什么东东&#xff1f; IOC&#xff08;Inversion of Control) 翻译过来叫控制反转。DI&#xff08;Dependency Injection&#xff09;翻译过来叫依赖注入。这时候就应该掏出我们的人生三问了。 控制反转用人话说…

【数据结构】线性表的链式表示(单链表)

计算机考研408-数据结构笔记本之——第二章 线性表 2.3 线性表的链式表示&#xff08;单链表的定义、基本操作&#xff1a;初始化/插入/删除/查找与建立&#xff09;

苹果 iOS / iPadOS 18 beta8和iOS / iPadOS 18.1 beta3版本更新

苹果今日向iPhone和iPad用户推送了 iOS / iPadOS 18 开发者预览版 Beta 8 更新&#xff08;内部版本号&#xff1a;22A5350a&#xff09;和iOS / iPadOS 18.1 开发者预览版 Beta 3 更新&#xff08;内部版本号&#xff1a;22B5034e&#xff09;&#xff0c;本次更新距离上次发布…

Linux系统使用Docker compose搭建开源文档系统Paperless-ngx

文章目录 前言1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 前言 本文主要介绍如何在Linux系统本地部署Paperless-ngx开源文档管理系统&#xff0c;并结合cpolar内网穿透工具解决本地部署…

Oracle SYSAUX表空间使用率过高进行清理

巡检的时候发现SYSAUX表空间使用率超过了80%&#xff0c;将近达到了60G: TABLESPACE_NAME Allocated (MB) Free (MB) Used (MB) PERCENTFREE -------------------- -------------- ---------- ---------- ----------- SYSAUX 60440 7907 …