做高效能的父母网站/怎么做好网络销售
1.并查集的概论
定义:
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。
主要构成:
并查集主要由一个整型数组pre[ ]和两个函数find( )、join( )构成。
数组 pre[ ] 记录了每个点的前驱节点是谁,函数 find(x) 用于查找指定节点 x 属于哪个集合,函数 join(x,y) 用于合并两个节点 x 和 y 。
作用:
并查集的主要作用是求连通分支数(如果一个图中所有点都存在可达关系(直接或间接相连),则此图的连通分支数为1;如果此图有两大子图各自全部可达,则此图的连通分支数为2……)
2.用一个故事来引入并查集(“魔法学院的联盟”)
在遥远的阿尔多王国,有一座声名远扬的魔法学院——天星学院。这所学院不仅教授强大的魔法,还拥有许多古老的传说。传说中提到,曾经有一个神秘的魔法师,名叫艾尔文,他发明了一种神奇的魔法工具,叫做“并查集”。
故事发生在天星学院的一个风和日丽的早晨,学院的学生们正忙于准备即将到来的年度魔法比赛。比赛的内容是让学生们组成小组进行各种挑战,争夺“学院最佳团队”的荣誉。
艾伦和他的朋友们被分配到了同一个小组,但在比赛前的准备中,他们发现学院里有多个小组已经相互合作,形成了若干个强大的联盟。这些联盟的存在让他们感到有些困惑,因为他们不知道如何将所有的合作伙伴都联系起来,从而提高自己的团队实力。
就在他们为此感到苦恼时,学院的长者向他们介绍了一种古老的魔法——并查集。长者解释说,并查集是一种强大的魔法工具,可以帮助他们轻松地管理和合并不同的联盟。
艾伦和他的朋友们认真听取了长者的讲解,并决定尝试使用这种魔法。他们发现,并查集的核心在于两个主要操作:
- 合并(Union):当两个小组决定合作时,他们可以通过这个操作将两个小组合并成一个更强大的联盟。
- 查找(Find):当他们需要知道某个小组是否已经与其他小组在同一个联盟中时,可以使用这个操作来检查。
使用了并查集的魔法后,艾伦和他的团队发现管理各个小组变得更加简单。他们能够迅速地找到已经存在的联盟,并根据需要进行合并。这使得他们能够更好地协调和组织自己的资源,形成了一个强大的联盟。
随着比赛的进行,艾伦和他的团队利用并查集的魔法成功地将所有的小组整合到一起,形成了一个无敌的联盟。他们在比赛中表现出色,最终赢得了“学院最佳团队”的荣誉。
在获胜的庆祝会上,艾伦和他的朋友们感慨万千,他们深刻理解了并查集魔法的强大力量,也明白了团队合作的重要性。从那以后,天星学院的学生们都学会了如何使用并查集来解决各种复杂的联盟问题,而艾伦和他的团队也因为这次经历成为了学院的传奇人物。
3.从数据结构的方向看并查集
-
查找(Find):确定一个元素属于哪个集合,通常返回集合的代表元素或根节点。此操作可以通过路径压缩优化,使得树的高度保持较小,从而提高查找效率。
-
合并(Union):将两个集合合并为一个集合。合并操作可以通过按秩合并(按树的深度合并)或按大小合并(合并小的树到大的树)来优化,从而保持数据结构的效率。
并查集常用于处理动态连通性问题,例如在图论中的连通分量计算。通过这些操作,并查集能够在接近常数时间内完成集合的合并和查找。
3.find()函数的定义与实现
find()
函数用于确定一个元素所在的集合的代表元素或根节点。它通常通过路径压缩优化来提高效率。
开始时每个集合都是一个独立的集合,并且都是等于自己本身下标的数
例如:
p[5]=5,p[3]=3;
如果是M操作的话那么就将集合进行合并,合并的操作是:
p[3]=p[5]=5;
所以3的祖宗节点便成为了5
此时以5为祖宗节点的集合为{5,3}
如果要将p[9]=9插入到p[3]当中,应该找到3的祖宗节点,
然后再把p[9]=9插入其中,所以p[9]=find(3);(find()函数用于查找祖宗节点)
也可以是p[find(9)]=find(3),因为9的节点本身就是9
此时以5为祖宗节点的集合为{5,3,9};
如果碰到多个数的集合插入另一个集合当中其原理是相同的
例如:
上述中以5为祖宗节点的是p[5],p[3],p[9];(即p[5]=5,p[3]=5,p[9]=5)
再构造一个以6为祖宗节点的集合为{6,4,7,10}
如果要将以6为祖宗节点的集合插入到以5为祖宗节点的集合,则该操作可以是
p[6]=find(3)(或者find(9),find(5))
此时p[6]=5
当然如果是以6为祖宗节点集合中的4,7,10则可以这样
p[find(4)]=find(3)
或者p[find(7)]=find(3)均可以
此时以6为祖宗节点的集合的祖宗节点都成为了5
3.2find()函数的实现
第一个find函数同时也运用了状态压缩即:
find 函数不仅有找祖宗的功能,还把这个查找路径上所有节点直接变成了祖宗节点的孩子
int find(int x)
{if(p[x]!=x) p[x]=find(p[x]);/*经上述可以发现,每个集合中只有祖宗节点的p[x]值等于他自己,即:p[x]=x;*/return p[x];//找到了便返回祖宗节点的值
}2.
int find(int x) //查找x的祖宗结点
{while(pre[x] != x) //如果x的上级不是祖宗节点x = pre[x]; //x继续找return x;
}
4.合并集合的代码实现与逻辑
- 先查找两个元素
x
和y
的根节点。- 比较两个根节点的秩(高度),将秩较小的根节点的树合并到秩较大的根节点的树下,确保树的高度尽可能低。
- 如果两个根节点的秩相同,将其中一个根节点设置为另一个根节点的子节点,并将该根节点的秩加一。
//合并a b所在的两个集合
void merge(int a, int b)
{int pa = find(a);//找到 a 所在集合的代表元素int pb = find(b);//找到 b 所在集合的代表元素if(pa != pb)//如果不是同一个,则属于不同集合,需要合并{p[pa] = pb;//将a所在集合代表元素的代表元素设置为b所在集合的代表元素。}
}
5.并查集的测试代码(进行了按秩合并的写法)
#include <vector>
#include <iostream>class DisjointSet {
public:DisjointSet(int size) : parent(size), rank(size, 1) {// 初始化每个元素的父节点指向自己for (int i = 0; i < size; ++i) {parent[i] = i;}}// 查找元素 x 所在集合的根节点,并进行路径压缩int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]); // 路径压缩}return parent[x];}// 合并两个集合void unionSets(int x, int y) {int rootX = find(x); // 查找 x 的根节点int rootY = find(y); // 查找 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] += 1;}}}private:std::vector<int> parent; // 记录每个元素的父节点std::vector<int> rank; // 记录每个树的秩
};int main() {DisjointSet ds(10); // 初始化一个包含10个元素的并查集ds.unionSets(1, 2); // 合并集合 {1} 和 {2}ds.unionSets(2, 3); // 合并集合 {1, 2} 和 {3}ds.unionSets(4, 5); // 合并集合 {4} 和 {5}// 检查合并后的结果std::cout << "Find 1: " << ds.find(1) << std::endl; // 输出 1std::cout << "Find 3: " << ds.find(3) << std::endl; // 输出 1std::cout << "Find 4: " << ds.find(4) << std::endl; // 输出 4std::cout << "Find 5: " << ds.find(5) << std::endl; // 输出 4ds.unionSets(3, 5); // 合并集合 {1, 2, 3} 和 {4, 5}// 检查合并后的结果std::cout << "Find 5 after union with 3: " << ds.find(5) << std::endl; // 输出 1,因为 1 和 5 现在在同一集合中return 0;
}
6.简单的实现代码(没有使用按秩合并的写法)
#include <vector>
#include <iostream>class DisjointSet {
public:DisjointSet(int size) : parent(size) {for (int i = 0; i < size; ++i) {parent[i] = i; // 每个元素的父节点初始化为自身}}// 查找元素 x 所在集合的根节点,并进行路径压缩int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]); // 路径压缩}return parent[x];}// 合并 a 和 b 所在的两个集合void merge(int a, int b) {int rootA = find(a); // 查找 a 所在集合的代表元素int rootB = find(b); // 查找 b 所在集合的代表元素if (rootA != rootB) {parent[rootB] = rootA; // 直接将 b 的根节点挂到 a 的根节点下}}private:std::vector<int> parent; // 记录每个元素的父节点
};int main() {DisjointSet ds(10); // 初始化一个包含10个元素的并查集ds.merge(1, 2); // 合并集合 {1} 和 {2}ds.merge(2, 3); // 合并集合 {1, 2} 和 {3}ds.merge(4, 5); // 合并集合 {4} 和 {5}// 检查合并后的结果std::cout << "Find 1: " << ds.find(1) << std::endl; // 输出 1std::cout << "Find 3: " << ds.find(3) << std::endl; // 输出 1std::cout << "Find 4: " << ds.find(4) << std::endl; // 输出 4std::cout << "Find 5: " << ds.find(5) << std::endl; // 输出 4ds.merge(3, 5); // 合并集合 {1, 2, 3} 和 {4, 5}// 检查合并后的结果std::cout << "Find 5 after union with 3: " << ds.find(5) << std::endl; // 输出 1,因为 1 和 5 现在在同一集合中return 0;
}
7.一些基本操作的实现
const int N=1005 //指定并查集所能包含元素的个数(由题意决定)
int pre[N]; //存储每个结点的前驱结点
int rank[N]; //树的高度
void init(int n) //初始化函数,对录入的 n个结点进行初始化
{for(int i = 0; i < n; i++){pre[i] = i; //每个结点的上级都是自己 rank[i] = 1; //每个结点构成的树的高度为 1 }
}
int find(int x) //查找结点 x的根结点
{if(pre[x] == x) return x; //递归出口:x的上级为 x本身,则 x为根结点 return find(pre[x]); //递归查找
} int find(int x) //改进查找算法:完成路径压缩,将 x的上级直接变为根结点,那么树的高度就会大大降低
{if(pre[x] == x) return x; //递归出口:x的上级为 x本身,即 x为根结点 return pre[x] = find(pre[x]); //此代码相当于先找到根结点 rootx,然后 pre[x]=rootx
} bool isSame(int x, int y) //判断两个结点是否连通
{return find(x) == find(y); //判断两个结点的根结点(即代表元)是否相同
}bool join(int x,int y)
{x = find(x); //寻找 x的代表元y = find(y); //寻找 y的代表元if(x == y) return false; //如果 x和 y的代表元一致,说明他们共属同一集合,则不需要合并,返回 false,表示合并失败;否则,执行下面的逻辑if(rank[x] > rank[y]) pre[y]=x; //如果 x的高度大于 y,则令 y的上级为 xelse //否则{if(rank[x]==rank[y]) rank[y]++; //如果 x的高度和 y的高度相同,则令 y的高度加1pre[x]=y; //让 x的上级为 y}return true; //返回 true,表示合并成功
}
相关文章:

【算法】并查集的介绍与使用
1.并查集的概论 定义: 并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。比如说,我们可以用并查集来判断一个森林中有几棵树、某个节点是否属于某棵树等。 主要构成: …...

Shell——运算符
在 Shell 编程中,运算符用于执行各种类型的操作,如算术运算、字符串比较、文件测试等。以下是 Shell 中常用的运算符分类和示例: 1. 算术运算符 Shell 中使用 expr 或 $(( ... )) 来进行算术运算。 : 加法-: 减法*: 乘法/: 除法%: 取余**:…...

SweetAlert2
1. SweetAlert2 SweetAlert2是一个基于JavaScript的库, 用于在网页上替换标准的警告框(alert), 确认框(confirm)和提示框(prompt), 并提供更加美观和用户友好的界面.需要在项目中引入SweetAlert2, 可以通过CDN链接或者将库文件下载到你的项目中来实现这一点. 通过CDN引入:<…...

c语言中比较特殊的输入函数
目录 一.getchar()函数 1.基本功能 2.使用方法 (1).读取单个字符 (2).读取多个字符(直到遇到换行符) (3).处理输入中的空白字符 3.返回值 4.应用场景 5.注意事项 二.fgets()函数 1.函数原型 2.工作原理 3.使用示例 (1).从标准输入读取一行…...

Java版自动化测试之Selenium
1. 准备 编程语言:Java JDK版本:17 Maven版本:3.6.1 2. 开始 声明:本次只测试Java的Selenium自动化功能 本次示例过程:打开谷歌游览器,进入目标网址,找到网页的输入框元素,输入指…...

【计算机网络】——计算机网络的性能指标
速率(speed) 连接在计算机网络上的主机在数字信道上传送数据的速率。 影响条件: 带宽(band width) 指在固定的时间可传输的资料数量 单位:bps或HZ 吞吐量(throughtput) 指对网络、…...

MongoDB数据类型介绍
MongoDB作为一种高性能、开源、无模式的文档型数据库,支持丰富的数据类型,以满足各种复杂的数据存储需求。本文将详细介绍MongoDB支持的主要数据类型,包括数值类型、字符串类型、日期和时间类型、布尔类型、二进制类型、数组、对象以及其他扩…...

【SpringBoot】SpringBoot 中 Bean 管理和拦截器的使用
目录 1.Bean管理 1.1 自定义Bean对象 1.2 Bean的作用域和生命周期 2.拦截器的使用 1.Bean管理 默认情况下,Spring项目启动时,会把我们常用的Bean都创建好放在IOC容器中,但是有时候我们自定义的类需要手动配置bean,这里主要介绍…...

Spring IoCDI(中)--IoC的进步
通过上文的讲解和学习, 我们已经知道了Spring IoC 和DI的基本操作, 接下来我们来系统的学习Spring IoC和DI 的操作. 前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对 象,也就是bean的存储。 1. Bean的…...

读软件开发安全之道:概念、设计与实施02经典原则
1. CIA原则 1.1. 软件安全都构建在信息安全的三大基本原则之上,即机密性(confidentiality)、完整性(integrity)和可用性(availability) 1.2. 双方交换的数据 1.2.1. 从技术上看,端点之间的数据交换本身就会削弱交互的机密性 1.2.2. 隐藏通信数据量的一…...

MySQL中处理JSON数据:大数据分析的新方向,详解与示例
文章目录 1. MySQL中的JSON数据类型2. JSON函数和运算符3. 创建JSON列的表4. 插入JSON数据5. 查询JSON数据6. 复杂查询和聚合7. JSON 数据的索引8. 总结 在当今的大数据时代,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式&a…...

【图形学】TA之路-矩阵
在 Unity 中,矩阵广泛用于处理各种图形变换,例如平移、旋转、缩放等。矩阵的使用不仅限于三维空间,还可以应用于二维空间的操作。了解矩阵及其运算对于游戏开发和计算机图形学非常重要。Unity 中使用的是行向量不是列向量,这个要注…...

LAMM: Label Alignment for Multi-Modal Prompt Learning
系列论文研读目录 文章目录 系列论文研读目录文章题目含义AbstractIntroductionRelated WorkVision Language ModelsPrompt Learning MethodologyPreliminaries of CLIPLabel AlignmentHierarchical Loss 分层损失Parameter Space 参数空间Feature Space 特征空间Logits Space …...

mac编译opencv 通用架构库的记录
1,通用架构 (x86_64;arm64)要设置的配置项: CPU_BASELINE CPU_DISPATCH 上面这两个我设置成SSE_3,其他选项未尝试,比如不设置。 CMAKE_OSX_ARCHITECTURES:x86_64;arm64 WITH_IPP:不勾选 2,contrib库的添加: 第一次…...

Python 向IP地址发送字符串
Python 向IP地址发送字符串 在网络编程中,使得不同设备间能够进行数据传输是一项基本任务。Python提供了强大的库,帮助开发者轻松地实现这种通信。本文将介绍如何使用Python通过UDP协议向特定的IP地址发送字符串信息。 UDP协议简介 UDP(用…...

上升响应式Web设计:纯HTML和CSS的实现技巧-1
响应式Web设计(Responsive Web Design, RWD)是一种旨在确保网站在不同设备和屏幕尺寸下都能良好运行的网页设计策略。通过纯HTML和CSS实现响应式设计,主要依赖于媒体查询(Media Queries)、灵活的布局、可伸缩的图片和字…...

利用java结合python实现gis在线绘图,主要技术java+python+matlab+idw+Kriging
主要技术javapythonmatlabidwKriging** GIS中的等值面和等高线绘图主要用于表达连续空间数据的分布情况,特别适用于需要展示三维空间中某个变量随位置变化的应用场景。 具体来说,以下是一些适合使用GIS等值面和等高线绘图的场景: 地形与地貌…...

Android全面解析之context机制(三): 从源码角度分析context创建流程(下)
前言 前面已经讲了什么是context以及从源码角度分析context创建流程(上)。限于篇幅把四大组件中的广播和内容提供器的context获取流程放在了这篇文章。广播和内容提供器并不是context家族里的一员,所以他们本身并不是context,因而…...

执行docker compose命令出现 Additional property include is not allowed
问题背景 在由docker-compose.yml的文件目录下执行命令 docker compose up -d 出现错误 Additional ininoperty include is not allowed 原因 我的docker-compose.yml 文件中出现了include标签旧版本的docker-compose 不支持此标签 解决办法 下载支持的docker-compose 解决…...

STM32通过I2C硬件读写MPU6050
目录 STM32通过I2C硬件读写MPU6050 1. STM32的I2C外设简介 2. STM32的I2C基本框图 3. STIM32硬件I2C主机发送流程 10位地址与7位地址的区别 7位主机发送的时序流程 7位主机接收的时序流程 4. STM32硬件与软件的波形对比 5. STM32配置硬件I2C外设流程 6. STM32的I2C.h…...

ubuntu2204-中文输入法-pycharm-python-django开发环境搭建
文章目录 1.系统常用设置1.1.安装中文输入法1.2.配置输入法1.3.卸载输入法1.4.配置镜像源2.java安装3.pycharm安装与启动4.卸载ubuntu2204默认版本5.安装Anaconda5.1.安装软件依赖包5.2.安装命令5.3.激活安装5.4.常用命令5.5.修改默认启动源6.安装mysql6.1.离线安装mysql6.2.在…...

【学习笔记】Matlab和python双语言的学习(一元线性回归)
文章目录 前言一、一元线性回归回归分析的一般步骤一元线性回归的基本形式回归方程参数的最小二乘法估计对回归方程的各种检验估计标准误差的计算回归直线的拟合优度判定系数显著性检验 二、示例三、代码实现----Matlab四、代码实现----python回归系数的置信区间公式残差的置信…...

LeetCode //C - 316. Remove Duplicate Letters
316. Remove Duplicate Letters Given a string s, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results. Example 1: Input: s “bcabc”…...

【ARM+Codesys 客户案例 】RK3568/A40i/STM32+CODESYS在工厂自动化中的应用:PCB板焊接机
现代化生产中,电子元件通常会使用自动化设备来进行生产,例如像PCB(印刷电路板)的组装。但是生产过程中也会面临一些问题,类似于如何解决在PCB板上牢固、精准地安装各种组件呢?IBL Lttechnik GmbH公司的CM80…...

【二分查找】--- 初阶题目赏析
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: 算法Joureny 上篇我们讲解了关于二分的朴素模板和边界模板,本篇博客我们试着运用这些模板。 🏠 搜索插入位置 📌 题目…...

【PostgreSQL003】PostgreSQL数据表空间膨胀,磁盘爆满,应用宕机(经验总结,已更新)
1.一直以来想写下基于PostgreSQL的系列文章,作为较火的数据ETL工具,也是日常项目开发中常用的一款工具,最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下PostgreSQL数据库相关知识体系。空间膨胀(主键、外键、…...

C语言第20天笔记
文件操作 概述 什么是 文件 文件时保存在外存储器上(一般代指磁盘,也可以是U盘、移动硬盘等)的数据的集合。 文件操作体现在哪几个方面 1. 文件内容的读取 2. 文件内容的写入 数据的读取和写入可被视为针对文件进行输入和输出的操作&a…...

为什么穷大方
为什么有些人明明很穷,却非常的大方呢? 因为他们认知太低,根本不懂钱的重要性,总是想着及时享乐,所以一年到头也存不了什么钱。等到家人孩子需要用钱的时候,什么也拿不出来,还到处去求人。 而真…...

HiveSQL实战——大数据开发面试高频SQL题
查询每个区域的男女用户数 0 问题描述 每个区域内男生、女生分别有多少个 1 数据准备 use wxthive; create table t1_stu_table (id int,name string,class string,sex string ); insert overwrite table t1_stu_table values(4,张文华,二区,男),(3,李思雨,一区,女),(1…...

RabbitMQ集群 - 普通集群搭建、宕机情况
文章目录 RabbitMQ 普通集群概述集群搭建数据准备启动容器宕机情况 RabbitMQ 普通集群 概述 1)普通模式中所有节点没有主从之分,所有节点的元数据(交换机、队列、绑定等)都是一致的. 例如只要有任意一个节点上面 新增交换机&…...