当前位置: 首页 > news >正文

[C++][数据结构][图][中][图的遍历][最小生成树]详细讲解

目录

  • 1.图的遍历
    • 1.广度优先遍历
    • 2.深度优先遍历
  • 2.最小生成树
    • 1.Kruskal算法
    • 2.Prim算法


1.图的遍历

  • 给定一个图G和其中任意一个顶点 v 0 v_0 v0,从 v 0 v_0 v0出发,沿着图中各边访问图中的所有顶点,且每个顶 点仅被遍历一次
    • “遍历”:对结点进行某种操作的意思

1.广度优先遍历

请添加图片描述

  • **例如:**现在要找东西,假设有三个抽屉,东西在哪个抽屉不清楚,现在要将其找到,广度优先遍历的做法是:

    1. 先将三个抽屉打开,在最外层找一遍
    2. 将每个抽屉中红色的盒子打开,再找一遍
    3. 将红色盒子中绿色盒子打开,再找一遍
    4. 直到找完所有的盒子
      • 注意:每个盒子只能找一次,不能重复找
        请添加图片描述
  • 思考:如何防止节点被重复遍历?

    • 增加一个数组,用于标记是否入过队列,这样可以防止重复遍历
void BFS(const V& src)
{size_t srci = GetVertexIndex(src);queue<int> q;vector<bool> visited(_vertexs.size(), false); // 标记数组q.push(srci);visited[srci] = true;int levelSize = 1; // 控制每层出的数量while (!q.empty()){// 一层一层出for (size_t i = 0; i < levelSize; i++){int front = q.front();q.pop();cout << front << ":" << _vertexs[front] << " ";// 把front的邻接顶点入队列for (size_t j = 0; j < _vertexs.size(); j++){if (_matrix[front][j] != MAX_W && visited[j] == false){q.push(j);visited[j] = true;}}}cout << endl;levelSize = q.size();}
}

2.深度优先遍历

请添加图片描述

  • **例如:**现在要找东西,假设有三个抽屉,东西在哪个抽屉不清楚,现在要将其找到,深度优先遍历的做法是:
    1. 先将第一个抽屉打开,在最外层找一遍
    2. 将第一个抽屉中红盒子打开,在红盒子中找一遍
    3. 将红盒子中绿盒子打开,在绿盒子中找一遍
    4. 递归查找剩余的两个盒子
    • **深度优先遍历:**将一个抽屉一次性遍历完(包括该抽屉中包含的小盒子),再去递归遍历其他盒子
  • 如果给的图不是连通图,以某个顶点为起点没有遍历完成,怎么保证遍历完剩下的顶点
    • 在visited数组中找没有遍历过的顶点,再次进行遍历
void _DFS(size_t srci, vector<bool>& visited)
{cout << srci << ":" << _vertexs[srci] << endl;visited[srci] = true;for (size_t i = 0; i < _vertexs.size(); i++){if (_matrix[i] != MAX_W && visited[i] == false){_DFS(i, visited);}}
}void DFS(const V& src)
{size_t srci = GetVertexIndex(src);vector<bool> visited(_vertexs.size(), false);_DFS(srci, visited);// 处理存在不连通的情况for (size_t i = 0; i < _vertexs.size(); i++){if (!visited[i]){_DFS(i, visited);}}
}

2.最小生成树

  • 连通图中的每一棵生成树,都是原图的一个极大无环子图,即:
    • 从其中删去任何一条边,生成树就不在连通
    • 反之,在其中引入任何一条新边,都会形成一条回路
  • 若连通图由n个顶点组成,则其生成树必含n个顶点和n-1条边,因此构造最小生成树的准则有三条:
    • 只能使用图中权值最小的边来构造最小生成树
      • 最小的成本让着N个顶点连通
    • 只能使用恰好n-1条边来连接图中的n个顶点
    • 选用的n-1条边不能构成回路
  • 构造最小生成树的方法:Kruskal算法和Prim算法,这两个算法都采用了逐步求解的贪心策略
  • 贪心算法:
    • 指在问题求解时,总是做出当前看起来最好的选择
      • 即:贪心算法做出的不是整体最优的的选择,而是某种意义上的局部最优解
    • 贪心算法不是对所有的问题都能得到整体最优解

1.Kruskal算法

  • 任给一个有n个顶点的连通网络 N = { V , E } N=\{V,E\} N={V,E}
    • 首先构造一个由这n个顶点组成、不含任何边的图 G = { V , N U L L } G=\{V,NULL\} G={V,NULL},其中每个顶点自成一个连通分量
    • 其次不断从E中取出权值最小的一条边(若有多条任取其一),若该边的两个顶点来自不同的连通分量,则将此边加入到G中
      • 如此重复,直到所有顶点在同一个连通分量上为止
    • 核心每次迭代时,选出一条具有最小权值,且两端点不在同一连通分量上的边,加入生成树
      • Kruskal算法是一种全局贪心的算法
  • 如何判断是否形成环?
    • 并查集
  • 在下图执行Kruskal算法的过程
    • 加了阴影的边属于不断增长的森林A
    • 该算法按照边的权重大小依次进行考虑,箭头指向的边是算法每一步考察的边
      • 如果该条边将两颗不同的树连接起来,它就被加入到森林里,从而完成对两棵树的合并
        请添加图片描述
W Kruskal(Self& minTree)
{size_t n = _vertexs.size();// 初始化minTreeminTree._vertexs = _vertexs;minTree._indexMap = _indexMap;minTree._matrix.resize(n);for (size_t i = 0; i < n; i++){minTree._matrix[i].resize(n, MAX_W);}priority_queue<Edge, vector<Edge>, greater<Edge>> minQueue;// 建堆排序for (size_t i = 0; i < n; i++){for (size_t j = 0; j < n; j++){if (i < j && _matrix[i][j] != MAX_W){minQueue.push(Edge(i, j, _matrix[i][j]));}}}// 选出n-1条边size_t size = 0;W totalW = W();UnionFindSet ufs(n);while (!minQueue.empty()){Edge min = minQueue.top();minQueue.pop();// 判环 -> 并查集if (!ufs.InSameSet(min._srci, min._dsti)){cout << _vertexs[min._srci] << "->" \<< _vertexs[min._dsti] << ":" << min._w << endl;minTree._AddEdge(min._srci, min._dsti, min._w);ufs.Union(min._srci, min._dsti); // 入集size++;totalW += min._w;}else{cout << "Forming Ring: ";cout << _vertexs[min._srci] << "->" \<< _vertexs[min._dsti] << ":" << min._w << endl;}}if (size == n - 1){return totalW;}else{return W();}
}

2.Prim算法

  • Prim算法的一个性质集合A中的边总是构成一棵树,这棵树从一个任意的根节点r开始,一直长大到覆盖V中的所有结点时为止
    • Prim算法思路天然避环
    • 算法每一步在连续集合A和A之外的结点的所有边中,选择一条轻量级边加入到A中
    • 本策略也属于贪心策略,因为每一步所加入的边都必须是使树的总权重增加量最小的边
      • Prim算法是一种局部贪心算法
  • 在下图执行Prim算法的过程
    • 初始的根节点为a,加阴影的边和黑色的结点都属于树A
    • 在算法的每一步,树中的结点就决定了图的一个切割,横跨该切割的一条轻量级边被加入到树中
    • **例如:**在途中第二步,该算法可以选择将边 ( b , c ) (b, c) (b,c)加入到树中,也可以将边 ( a , h ) (a, h) (a,h)加入到树中,因为这两条边都是横跨该切割的轻量级边
      请添加图片描述
W Prim(Self& minTree, const W& src)
{size_t srci = GetVertexIndex(src);size_t n = _vertexs.size();// 初始化minTreeminTree._vertexs = _vertexs;minTree._indexMap = _indexMap;minTree._matrix.resize(n);for (size_t i = 0; i < n; i++){minTree._matrix[i].resize(n, MAX_W);}// true & false表示该元素是否在该集合内vector<bool> X(n, false);vector<bool> Y(n, true);X[srci] = true;Y[srci] = false;// 从X->Y集合中连接的边里面选出最小的边priority_queue<Edge, vector<Edge>, greater<Edge>> minQueue;// 先把srci连接的边添加到队列中for (size_t i = 0; i < n; i++){if (_matrix[srci][i] != MAX_W){minQueue.push(Edge(srci, i, _matrix[srci][i]));}}size_t size = 0;W totalW = W();while (!minQueue.empty()){Edge min = minQueue.top();minQueue.pop();// 最小边的目标也在X集合,则构成环if (X[min._dsti]){cout << "Forming Ring:";cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;}else{cout << _vertexs[min._srci] << "->" << _vertexs[min._dsti] << ":" << min._w << endl;minTree._AddEdge(min._srci, min._dsti, min._w);X[min._dsti] = true;Y[min._dsti] = false;size++;totalW += min._w;// 可能最小生成树已经生成,但是多了很多成环边,无须继续遍历if (size == n - 1){break;}// 将目标顶点连接的边加入到队列中for (size_t i = 0; i < n; i++){if (_matrix[min._dsti][i] != MAX_W && Y[i]){minQueue.push(Edge(min._dsti, i, _matrix[min._dsti][i]));}}}}// 实际不一定存在最小生成树if (size == n - 1){return totalW;}else{return W();}
}

相关文章:

[C++][数据结构][图][中][图的遍历][最小生成树]详细讲解

目录 1.图的遍历1.广度优先遍历2.深度优先遍历 2.最小生成树1.Kruskal算法2.Prim算法 1.图的遍历 给定一个图G和其中任意一个顶点 v 0 v_0 v0​&#xff0c;从 v 0 v_0 v0​出发&#xff0c;沿着图中各边访问图中的所有顶点&#xff0c;且每个顶 点仅被遍历一次 “遍历”&…...

退市新规解读—财务类强制退市

一、退市风险警示&#xff1a;第一年触及相关指标 上市公司最近一个会计年度触及下列退市风险指标之一&#xff0c;公司股票或存托凭证被实施退市风险警示(*ST)&#xff1a; 第1项 组合类财务指标 仅发行A股或B股&#xff0c;最近一个会计年度或追溯重述后最近一个会计年度 …...

小程序的生命周期使用方法和应用场景

小程序生命周期 初始化&#xff08;App Launch&#xff09; • 触发时机&#xff1a;小程序首次启动时。 • 主要事件&#xff1a;onLaunch。 • 功能与适用场景&#xff1a; • 全局数据初始化&#xff1a;设置应用的全局状态和变量。 • 登录状态检查&#xff1a;判断用户是…...

什么是C++模块化系统?C++20的模块化系统。

C20引入的模块化系统是一种新的代码组织和编译机制&#xff0c;它旨在替代传统的头文件机制&#xff0c;提供更好的代码组织、更快的编译速度和更强的封装性。模块化系统的主要目标包括&#xff1a; 减少编译时间&#xff1a;通过减少冗余的头文件解析和宏定义传播&#xff0c…...

智慧校园-档案管理系统总体概述

智慧校园档案管理系统&#xff0c;作为教育信息化进程中的重要一环&#xff0c;它运用现代信息技术的力量&#xff0c;彻底改变了传统档案管理的面貌&#xff0c;为学校档案资源的收集、整理、存储、检索与利用开辟了全新的途径。这一系统全面覆盖学生、教职工、教学科研及行政…...

文心一言 VS 讯飞星火 VS chatgpt (290)-- 算法导论21.3 3题

三、给出一个包含 m 个 MAKE-SET 、UNION 和 FINDSET 操作的序列(其中有 n 个是 MAKE-SET 操作)&#xff0c;当仅使用按秩合并时&#xff0c;需要 Ω(mlgn) 的时间。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 在并查集&#xff08;Union-Find&#xff09;数…...

逻辑回归梯度推导

逻辑回归是一种广泛使用的分类算法&#xff0c;用于估计一个事件发生的概率。它是线性回归的扩展&#xff0c;通过sigmoid函数将线性回归的输出映射到[0, 1]区间&#xff0c;从而用于分类任务。 在逻辑回归中&#xff0c;我们使用对数似然损失函数&#xff08;log-likelihood l…...

Python 使用函数输出一个整数的逆序数

在Python中&#xff0c;你可以定义一个函数来输出一个整数的逆序数。这里有一个简单的实现方法&#xff1a; def reverse_integer(x):# 检查输入是否为整数if not isinstance(x, int):raise ValueError("Input must be an integer")# 将整数转换为字符串&#xff0c…...

【Linux】Wmware Esxi磁盘扩容

目录 一、概述 1.1 磁盘分区概念 1.2 LVM概念 二、扩容步骤 二、报错 一、概述 1.1 磁盘分区概念 在 Linux 中&#xff0c;每一个硬件设备都映射到一个系统的文件&#xff0c;对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux把各种 IDE 设备分配了一个由 hd 前缀组成的文…...

树莓派4B_OpenCv学习笔记15:OpenCv定位物体实时坐标

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 今日学习 OpenCv定位物体实时位置&#xff0c;代码来源是…...

MySQL之如何定位慢查询

1、如何定位慢查询 1.1、使用开源工具 调试工具&#xff1a;Arthas 运维工具&#xff1a;Promethuss、Skywalking 1.2、MySQL自带慢日志 慢查询日志记录了所有执行时间超过指定参数&#xff08;long_query_time&#xff0c;单位&#xff1a;秒&#xff0c;默认10秒&#x…...

Open3D 删除点云中重复的点

目录 一、算法原理1、重叠点2、主要函数二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、重叠点 原始点云克隆一份   构造重叠区域   合并点云获得重叠点 2、主要…...

填报志愿选专业是兴趣重要还是前景重要?

进行专业评估&#xff0c;找到一个适合自己的专业是一件非常困难的事情。在进行专业选择时&#xff0c;身上理想化色彩非常严重的人&#xff0c;会全然不顾及他人的劝阻&#xff0c;义无反顾的以兴趣为主&#xff0c;选择自己热爱的专业。一些较多考虑他人建议&#xff0c;能听…...

python开发基础——day9 函数基础与函数参数

一、初识函数(function) 编程函数!数学函数&#xff0c;里面的是逻辑&#xff0c;功能&#xff0c;而不是套公式 编程函数的作用实现特定操作的一段代码 你现在请客&#xff0c;每个人都点同样的一份吃的&#xff0c;请100个人 1.薯条 2.上校鸡块 3.可乐 那…...

STM32——使用TIM输出比较产生PWM波形控制舵机转角

一、输出比较简介&#xff1a; 只有高级定时器和通用寄存器才有输入捕获/输出比较电路&#xff0c;他们有四个CCR&#xff08;捕获/比较寄存器&#xff09;&#xff0c;共用一个CNT&#xff08;计数器&#xff09;&#xff0c;而输出比较功能是用来输出PWM波形的。 红圈部分…...

第十五章 集合(set)(Python)

文章目录 前言一、集合 前言 集合&#xff08;set&#xff09;是一个无序的不重复元素序列。 一、集合 set {1, 2, 3, 4}...

面试-javaIO机制

1.BIO BIO&#xff1a;是传统的javaIO以及部分java.net下部分接口和类。例如&#xff0c;socket,http等&#xff0c;因为网络通信同样是IO行为。传统IO基于字节流和字符流进行操作。提供了我们最熟悉的IO功能&#xff0c;譬如基于字节流的InputStream 和OutputStream.基于字符流…...

在.NET Core中,config和ConfigureServices的区别和作用

在.NET Core中&#xff0c;config和ConfigureServices是两个不同的概念&#xff0c;它们在应用程序的启动和配置过程中扮演着不同的角色。 ConfigureServices&#xff1a;这是ASP.NET Core应用程序中的一个方法&#xff0c;位于Startup类的内部。它的作用是配置依赖注入(DI)容器…...

App Inventor 2 如何实现多个定时功能?

1、可以使用多个“计时器”组件。 2、也可以用一个计时器&#xff0c;定时一分钟。也就是一分钟就会触发一次事件执行&#xff0c;定义一个全局数字变量&#xff0c;在事件中递增&#xff0c;用逻辑判断这个变量的值即可完成多个想要定时的任务(о∀о) 代码块请参考&#xf…...

技术驱动的音乐变革:AI带来的产业重塑

&#x1f4d1;引言 近一个月来&#xff0c;随着几款音乐大模型的轮番上线&#xff0c;AI在音乐产业的角色迅速扩大。这些模型不仅将音乐创作的门槛降至前所未有的低点&#xff0c;还引发了一场关于AI是否会彻底颠覆音乐行业的激烈讨论。从初期的兴奋到现在的理性审视&#xff0…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...

生信服务器 | 做生信为什么推荐使用Linux服务器?

原文链接&#xff1a;生信服务器 | 做生信为什么推荐使用Linux服务器&#xff1f; 一、 做生信为什么推荐使用服务器&#xff1f; 大家好&#xff0c;我是小杜。在做生信分析的同学&#xff0c;或是将接触学习生信分析的同学&#xff0c;<font style"color:rgb(53, 1…...

【笔记】结合 Conda任意创建和配置不同 Python 版本的双轨隔离的 Poetry 虚拟环境

如何结合 Conda 任意创建和配置不同 Python 版本的双轨隔离的Poetry 虚拟环境&#xff1f; 在 Python 开发中&#xff0c;为不同项目配置独立且适配的虚拟环境至关重要。结合 Conda 和 Poetry 工具&#xff0c;能高效创建不同 Python 版本的 Poetry 虚拟环境&#xff0c;接下来…...