图算法的概念
文章目录图算法概述拓扑排序拓扑排序的概念拓扑排序的实现方式拓扑排序的拓展场景最短路Bellman-Ford 算法Dijkstra 算法Floyd-Warshall 算法最小生成树Kruskal 算法Prim 算法目录图算法概述图算法是通过在图中按特定方式遍历得到答案的算法。已经介绍过的广度优先搜索和深度优先搜索是两种常见的图算法。除了两种搜索算法以外常见的图算法还有以下三种。拓扑排序适用于有向无环图图中的有向边决定顶点之间的相对顺序将图中的顶点按相对顺序排序。一些有环图和无向图的场景也可以使用拓扑排序。最短路适用于带权图计算从一个顶点到另一个顶点的权重最小的路径路径的权重为该路径经过的所有边的权重之和。当图中的所有边的权重都是1 11时退化为无权图此时的最短路算法等价于广度优先搜索算法。最小生成树适用于带权图在图中寻找一个包含所有顶点的无环连通树满足树中的所有边的权重之和最小这个树称为最小生成树。拓扑排序拓扑排序的概念拓扑排序是将有向无环图中的顶点排序得到有序线性序列的算法。图中的每条有向边决定了顶点之间的相对顺序如果有一条有向边从顶点u uu指向顶点v vv则拓扑排序的结果应满足顶点u uu出现在顶点v vv之前。在有向无环图中顶点之间的相对顺序是唯一的因此一定存在拓扑排序。同一个图可能有多种拓扑排序结果。例如下图的拓扑排序可能有以下结果[ 0 , 1 , 2 , 3 , 4 ] [0, 1, 2, 3, 4][0,1,2,3,4]、[ 0 , 1 , 3 , 2 , 4 ] [0, 1, 3, 2, 4][0,1,3,2,4]、[ 0 , 2 , 1 , 3 , 4 ] [0, 2, 1, 3, 4][0,2,1,3,4]。拓扑排序的实现方式拓扑排序可以基于广度优先搜索或深度优先搜索实现。基于广度优先搜索的拓扑排序做法如下。计算每个顶点的入度将入度为0 00的顶点入队列。每次将一个顶点出队列并添加到拓扑排序结果的末尾将该顶点的每个后继顶点的入度减1 11。如果后继顶点的入度变为0 00则将后继顶点入队列。重复上述操作当所有顶点都遍历过之后即可得到拓扑排序的结果。基于深度优先搜索的拓扑排序做法如下。从任意一个顶点开始执行深度优先搜索依次对该顶点的所有后继顶点执行深度优先搜索。当一个顶点的所有后继顶点都遍历过之后将该顶点添加到拓扑排序结果的前端。如果存在其他尚未访问的顶点则继续对尚未访问的顶点执行深度优先搜索。当所有顶点都遍历过之后即可得到拓扑排序的结果。拓扑排序的拓展场景除了有向无环图以外拓扑排序也适用于一些有环图和无向图的场景。如果有向图中存在环则环中的顶点循环依赖因此不存在拓扑排序的结果。使用拓扑排序可以判断有向图中是否存在环。对于无向图的场景可以从度为1 11的顶点开始执行拓扑排序寻找图的中心顶点。最短路带权图中每条边都有权重一条路径的权重为该路径经过的所有边的权重之和。最短路是在带权图中计算从一个顶点到另一个顶点的权重最小的路径的算法。如果图中存在权重为负的环且可以从源顶点到达该权重为负的环则不存在权重最小的路径。以下只考虑图中不存在权重为负的环的情况。常见的最短路算法包括 Bellman-Ford 算法、Dijkstra 算法和 Floyd-Warshall 算法。Bellman-Ford 算法和 Dijkstra 算法为单源最短路径算法Floyd-Warshall 算法为所有顶点对最短路径算法。以下用n nn表示图中的顶点数m mm表示图中的边数。Bellman-Ford 算法Bellman-Ford 算法是最简单的单源最短路径算法做法是对图中的所有边执行n − 1 n - 1n−1次遍历得到从源顶点到每个顶点的最短路径权重。创建长度为n nn的数组distances \textit{distances}distances作为结果数组记录从源顶点到每个顶点的最短路径权重用source \textit{source}source表示源顶点初始时distances [ source ] 0 \textit{distances}[\textit{source}] 0distances[source]0distances \textit{distances}distances中的其余元素都是∞ \infty∞。将遍历到的边的起点、终点和权重分别记为start \textit{start}start、end \textit{end}end和weight \textit{weight}weight如果distances [ start ] ≠ ∞ \textit{distances}[\textit{start}] \ne \inftydistances[start]∞且distances [ end ] distances [ start ] weight \textit{distances}[\textit{end}] \textit{distances}[\textit{start}] \textit{weight}distances[end]distances[start]weight则将distances [ end ] \textit{distances}[\textit{end}]distances[end]的值更新为distances [ start ] weight \textit{distances}[\textit{start}] \textit{weight}distances[start]weight。初始时可以确定源顶点source \textit{source}source对应的最短路径权重是0 00。每一次遍历之后可以确定图中的一个顶点对应的最短路径权重n − 1 n - 1n−1次遍历之后即可得到从源顶点到每个顶点的最短路径权重。使用 Bellman-Ford 算法时图中可以存在权重为负的边。Bellman-Ford 算法的时间复杂度是O ( n m ) O(nm)O(nm)空间复杂度是O ( 1 ) O(1)O(1)返回值不计入空间复杂度。Bellman-Ford 算法的实现如下。输入参数为边数组表示的图edges \textit{edges}edges、图中顶点数n nn和源顶点source \textit{source}source0 ≤ source n 0 \le \textit{source} n0≤sourcen。边数组中的每个元素是长度为3 33的数组[ i , j , w ] [i, j, w][i,j,w]表示图中存在一条权重是w ww的边( i , j ) (i, j)(i,j)。classSolution{publicint[]bellmanFord(int[][]edges,intn,intsource){int[]distancesnewint[n];Arrays.fill(distances,Integer.MAX_VALUE);distances[source]0;for(inti1;in;i){for(int[]edge:edges){intstartedge[0],endedge[1],weightedge[2];if(distances[start]!Integer.MAX_VALUEdistances[end]distances[start]weight){distances[end]distances[start]weight;}}}returndistances;}}Dijkstra 算法Dijkstra 算法是优化的单源最短路径算法做法是对图中的顶点执行n nn次循环得到从源顶点到每个顶点的最短路径权重。每次循环时从尚未确定最短路径权重的顶点中找到最短路径权重最小的顶点将该顶点的状态更新为确定最短路径权重并使用该顶点的最短路径权重更新该顶点的所有后继顶点的最短路径权重。由于每次循环都能确定一个顶点的最短路径权重因此经过n nn次循环之后即可得到每个顶点的最短路径权重。寻找最短路径权重最小的顶点有两种做法第一种做法是枚举所有尚未确定最短路径权重的顶点第二种做法是维护小根堆。使用 Dijkstra 算法时图中的所有边的权重都必须非负。Dijkstra 算法的时间复杂度是O ( n 2 ) O(n^2)O(n2)或O ( ( n m ) log ⁡ n ) O((n m) \log n)O((nm)logn)取决于实现方式是基于枚举实现还是基于小根堆实现空间复杂度是O ( n ) O(n)O(n)。Dijkstra 算法的基于枚举实现和基于小根堆实现如下。输入参数为邻接数组表示的图graph \textit{graph}graph和源顶点source \textit{source}source0 ≤ source n 0 \le \textit{source} n0≤sourcen。邻接数组的长度是n nn对于0 ≤ i n 0 \le i n0≤ingraph [ i ] \textit{graph}[i]graph[i]为所有以顶点i ii为起点的边的终点和权重的集合如果[ j , w ] ∈ graph [ i ] [j, w] \in \textit{graph}[i][j,w]∈graph[i]则图中存在一条权重是w ww的边( i , j ) (i, j)(i,j)。classSolution{publicint[]dijkstra(int[][][]graph,intsource){intngraph.length;int[]distancesnewint[n];Arrays.fill(distances,Integer.MAX_VALUE);distances[source]0;boolean[]visitednewboolean[n];for(inti0;in;i){intcurr-1;for(intj0;jn;j){if(!visited[j](curr0||distances[curr]distances[j])){currj;}}visited[curr]true;for(int[]adjacent:graph[curr]){intnextadjacent[0],weightadjacent[1];distances[next]Math.min(distances[next],distances[curr]weight);}}returndistances;}}classSolution{publicint[]dijkstra(int[][][]graph,intsource){intngraph.length;int[]distancesnewint[n];Arrays.fill(distances,Integer.MAX_VALUE);distances[source]0;PriorityQueueint[]pqnewPriorityQueueint[]((a,b)-a[1]-b[1]);pq.offer(newint[]{source,0});while(!pq.isEmpty()){int[]pairpq.poll();intcurrpair[0],distancepair[1];if(distances[curr]distance){continue;}for(int[]adjacent:graph[curr]){intnextadjacent[0],weightadjacent[1];if(distances[next]distanceweight){distances[next]distanceweight;pq.offer(newint[]{next,distances[next]});}}}returndistances;}}Floyd-Warshall 算法Floyd-Warshall 算法用于计算所有顶点对最短路径考虑最短路径的中间顶点。用distances [ i ] [ j ] \textit{distances}[i][j]distances[i][j]表示从顶点i ii到顶点j jj的最短路径权重。从顶点i ii到顶点j jj的最短路径有两种情况一是存在一条边( i , j ) (i, j)(i,j)二是从顶点i ii先到中间顶点k kk然后到顶点j jj。Floyd-Warshall 算法的具体做法是对于每个0 ≤ k n 0 \le k n0≤kn遍历每一对顶点( i , j ) (i, j)(i,j)当distances [ i ] [ j ] distances [ i ] [ k ] distances [ k ] [ j ] \textit{distances}[i][j] \textit{distances}[i][k] \textit{distances}[k][j]distances[i][j]distances[i][k]distances[k][j]时将distances [ i ] [ j ] \textit{distances}[i][j]distances[i][j]更新为distances [ i ] [ k ] distances [ k ] [ j ] \textit{distances}[i][k] \textit{distances}[k][j]distances[i][k]distances[k][j]遍历结束之后即可得到所有顶点对的最短路径权重。实现方面当给定的图是邻接矩阵时可以直接在邻接矩阵上更新所有顶点对的最短路径权重。使用 Floyd-Warshall 算法时图中可以存在权重为负的边。Floyd-Warshall 算法的时间复杂度是O ( n 3 ) O(n^3)O(n3)空间复杂度是O ( 1 ) O(1)O(1)返回值不计入空间复杂度。Floyd-Warshall 算法的实现如下。输入参数为邻接矩阵表示的图matrix \textit{matrix}matrix。矩阵的行数和列数都是n nn对于0 ≤ i , j n 0 \le i, j n0≤i,jnmatrix [ i ] [ j ] \textit{matrix}[i][j]matrix[i][j]的值如下。如果i j i jij则matrix [ i ] [ j ] 0 \textit{matrix}[i][j] 0matrix[i][j]0。如果i ≠ j i \ne jij且存在边( i , j ) (i, j)(i,j)则matrix [ i ] [ j ] \textit{matrix}[i][j]matrix[i][j]为边( i , j ) (i, j)(i,j)的权重。如果i ≠ j i \ne jij且不存在边( i , j ) (i, j)(i,j)则matrix [ i ] [ j ] ∞ \textit{matrix}[i][j] \inftymatrix[i][j]∞。classSolution{publicint[][]floydWarshall(int[][]matrix){intnmatrix.length;for(intk0;kn;k){for(inti0;in;i){for(intj0;jn;j){matrix[i][j]Math.min(matrix[i][j],matrix[i][k]matrix[k][j]);}}}returnmatrix;}}最小生成树无向带权连通图中的最小生成树是包含图中所有顶点的子图该子图为连通无环图子图中的所有边的权重之和最小由于子图满足连通和无环因此子图一定是树的结构。用n nn表示图中的顶点数则最小生成树包含n − 1 n - 1n−1条边且这些边的权重之和最小。同一个图中的最小生成树可能不唯一但是最小生成树中的边的权重之和最小值唯一。如果一个图中有多个可能的最小生成树则每个最小生成树中的边的权重之和相同。构建最小生成树的思想是初始时图中的n nn个顶点都是独立的每次选一条边加入最小生成树使得所选的边不形成环且权重之和最小重复n − 1 n - 1n−1次操作之后选定的n − 1 n - 1n−1条边将n nn个顶点连接得到最小生成树。构建最小生成树的算法有 Kruskal 算法和 Prim 算法。以下用n nn表示图中的顶点数m mm表示图中的边数。Kruskal 算法Kruskal 算法构建最小生成树的做法是每次在尚未选取的边中选取一条权重最小且不会产生环的边将这条边作为最小生成树中的一条边直到所有的顶点属于同一个连通分量。判断选取一条边是否会产生环的做法是判断这条边连接的两个顶点是否属于同一个连通分量如果属于同一个连通分量则选取这条边之后会产生环如果不属于同一个连通分量则选取这条边之后不会产生环。选取一条边之后需要将这条边连接的两个顶点合并到同一个连通分量。连通性问题可以使用并查集解决。并查集支持合并与查找的操作Kruskal 算法是并查集的应用场景之一。高级数据结构部分将会具体介绍并查集。Kruskal 算法的时间复杂度是O ( n m log ⁡ m ) O(n m \log m)O(nmlogm)空间复杂度是O ( n m ) O(n m)O(nm)。由于 Kruskal 算法的时间复杂度和边数有关因此 Kruskal 算法适用于边稀疏图。Prim 算法Prim 算法构建最小生成树的做法是任选一个顶点开始构建最小生成树初始时的最小生成树只有选定的顶点每次在尚未选取的顶点中选取与最小生成树连接的边的权重最小的顶点将该顶点和对应的边添加到最小生成树中直到所有顶点都被添加到最小生成树中此时的生成树为最小生成树。Prim 算法的时间复杂度是O ( n 2 ) O(n^2)O(n2)空间复杂度是O ( n ) O(n)O(n)。由于 Prim 算法的时间复杂度只和顶点数有关因此 Prim 算法适用于边稠密图。目录拓扑排序题目从给定原材料中找到所有可以做出的菜拓扑排序题目找到最终的安全状态拓扑排序题目最小高度树拓扑排序题目喧闹和富有拓扑排序题目项目管理拓扑排序题目奇怪的打印机 II最短路题目网络延迟时间最短路题目阈值距离内邻居最少的城市最短路题目使网格图至少有一条有效路径的最小代价最短路题目概率最大的路径最短路题目细分图中的可到达结点最小生成树题目连接所有点的最小费用最小生成树题目找到最小生成树里的关键边和伪关键边

相关新闻

Gorpc连接池原理:单个TCP连接如何承载40K QPS的底层技术

Gorpc连接池原理:单个TCP连接如何承载40K QPS的底层技术

Gorpc连接池原理:单个TCP连接如何承载40K QPS的底层技术 【免费下载链接】gorpc Simple, fast and scalable golang rpc library for high load 项目地址: https://gitcode.com/gh_mirrors/go/gorpc Gorpc作为一款轻量级高性能的Golang RPC库,通过…

2026/10/15 4:57:54 阅读更多 →
软件模拟9位UART实现Stellaris多机通信:原理、实现与优化

软件模拟9位UART实现Stellaris多机通信:原理、实现与优化

1. 项目概述与背景在嵌入式系统开发中,串行通信是连接微控制器与外部世界最基础、最常用的桥梁之一。UART(通用异步收发器)因其协议简单、硬件资源要求低、实现成本低廉,几乎成为了所有微控制器的标配外设。无论是调试信息打印、与…

2026/10/17 12:55:37 阅读更多 →
基于华为云 FlexusX 四节点集群的云计算全栈实操(二):云虚拟机性能基准(sysbench CPU/内存深度体检)

基于华为云 FlexusX 四节点集群的云计算全栈实操(二):云虚拟机性能基准(sysbench CPU/内存深度体检)

基于华为云 FlexusX 四节点集群的云计算全栈实操(二):云虚拟机性能基准(sysbench CPU/内存深度体检) 上篇我们把四节点实验室的地基打好了(自动化运维基建)。本篇进入 IaaS 层的真正硬核——给云…

2026/10/15 19:29:54 阅读更多 →

最新新闻

CSDN+AI:程序员新生产力的技术演进路径

CSDN+AI:程序员新生产力的技术演进路径

我需要先读取「7. 总结与展望」这一节的精确 HTML,以便在正确的位置补充完整内容。已在文章末尾完整补充「7. 总结与展望」章节,包含全文核心观点回顾、三个实战案例的关键收获、脚本质量与安全审查要点、未来 AI 辅助运维的发展趋势,以及给读…

2026/10/17 13:34:38 阅读更多 →
CTF隐写题入门:Base64隐写、LSB图片隐写与文件分离实战

CTF隐写题入门:Base64隐写、LSB图片隐写与文件分离实战

1. 隐写题的共性套路:拿到文件先别急着“看”CTF里的Misc(杂项)题目,说白了就是考“找藏起来的东西”。这个方向不像PWN和逆向那样门槛极高,但特别考验信息收集的完整度和对各种编码格式的敏感度。很多时候题目本身不难…

2026/10/17 13:34:38 阅读更多 →
图像切割与特征提取实战:从原始图像到特征矩阵的完整流程

图像切割与特征提取实战:从原始图像到特征矩阵的完整流程

1. 图像切割:拿到一张图,先想清楚要“切谁”1.1 切割在整个预处理链路里的位置“数据预处理与特征工程”这个系列写到这里,终于轮到图像切割与特征提取这对组合。很多人容易忽略一件事:图像任务里真正的胜负手,往往不在…

2026/10/17 13:34:38 阅读更多 →
传一个关键词,影刀自己上小红书搜图、翻笔记、点赞收藏发评论|AI 流程助手全链路复盘

传一个关键词,影刀自己上小红书搜图、翻笔记、点赞收藏发评论|AI 流程助手全链路复盘

目录引言研究背景与意义文献综述研究方法与设计数据收集与处理结果分析讨论与启示结论与展望参考文献附录摘要本研究聚焦于[具体研究主题],旨在探讨[核心问题或目标]。通过系统梳理相关文献,结合定量与定性相结合的研究方法,对[研究对象或数据…

2026/10/17 13:34:38 阅读更多 →
前端学习底层逻辑:从解决问题出发,构建稳固技术地基

前端学习底层逻辑:从解决问题出发,构建稳固技术地基

1. 先别急着列技术清单:前端学习的底层逻辑1.1 我把问题从"学什么"改成了"解决什么"时不时有人带着一张截图来找我,上面密密麻麻列着几十项技术名词,问我说"这些是不是都得学,哪个先学哪个后学"。我…

2026/10/17 13:34:38 阅读更多 →
并行优化算法研究PPT深度拆解:知识框架、算法分类与性能优化避坑指南

并行优化算法研究PPT深度拆解:知识框架、算法分类与性能优化避坑指南

简介:这份演示文稿聚焦并行优化算法,面向需要入门并行计算与智能优化方法的开发者、研究生及相关从业者,系统梳理了该领域的核心知识体系。内容从并行优化算法的发展历程与基本原理入手,覆盖并行计算的硬件与软件基础,…

2026/10/17 13:33:37 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →