最短路径(Dijkstra算法与Floyd算法)

大话数据结构-迪杰斯特拉算法(Dijkstra)和弗洛伊德算法(Floyd) 最短路径,迪杰斯特拉算法(Dijkstra)、弗洛伊德算法(Floyd)基本原理及邻接矩阵的代码实现。 阅读详情

一、Dijkstra算法

Dijkstra算法与之前学习过的Prim算法有些相似之处。我们直接通过一个例子来讲解

假设要求的是A->E之间的最短路径。首先我们来列出顶点A到其他各顶点的路径长度:A->D = 2,A->B = 6,A->C = 1,A->E = ∞。既然是要寻找最短路径,我们当然是先在已有的路径里面挑一条最短的,也就是A->C。将到达过的顶点用红色进行标识

到达C点后,我们又可以找到两条路径:C->B = 5,C->E = 7。此时我们拿这几条新的路径长度,与之前的A->C = 1相加,就可以得到A->B = 6,A->E = 8。出现了一条比之前短的路径:A->E = 8。所以我们将其更新到之前的路径列表里:A->D = 2,A->B = 6,A->C = 1,A->E = 8。

接下来再从路径列表里选择一条最短的路径,也就是:A->D = 2。将D标记为已到达。

到达D点后,又可以找到两条新的路径:D->B = 3,D->E = 6。与A->D = 2相加可得:A->B = 5,A-E = 8。又有一条比之前短的路径:A->B = 5,所以将其更新到路径列表:A->D = 2,A->B = 5,A->C = 1,A->E = 8。

再选择一条最短的路径:A->B = 5。将B标记为已到达。

这次只有一条新的路径:B->E = 2。将其与A->B = 5相加得:A->E = 7。比之前的路径更短,所以更新到路径列表:A->D = 2,A->B = 5,A->C = 1,A->E = 7。最后来到E点,结束遍历。

与此同时,我们获得了一张从A到各个顶点的最短路径长度表。

代码如下

public struct Path
{
	// 上一顶点下标
	public int preNode;
	// 起始顶点到当前顶点的总路径长度
	public int totalWeight;

	public Path(int preNode, int totalWeight)
	{
		this.preNode = preNode;
		this.totalWeight = totalWeight;
	}
}

/// <summary>  
/// Dijkstra算法  
/// </summary>  
/// <param name="graph"></param>  
/// <param name="startIndex"></param>
public Path[] Dijkstra<T>(GraphByAdjacencyMatrix<T> graph,int startIndex)
{
	// 用来存储顶点是否访问过
	bool[] flags = new bool[graph.Count];
	// 存储起始顶点到其他各顶点的最短路径长度
	Path[] paths = new Path[graph.Count];

	// 初始化起始顶点到其他顶点的路径
	for (int i = 0; i < graph.Count; i++)
	{
		paths[i] = new Path(startIndex, graph.Matrix[startIndex, i]);
	}
	// 将初始顶点设为已访问
	flags[startIndex] = true;
	int minIndex = 0;
	
	for (int i = 1; i < graph.Count; i++)
	{
		int min = Int32.MaxValue;
		// 寻找已存储路径中的最短路径
		for (int j = 0; j < graph.Count; j++)
		{
			if (!flags[j] && paths[j].totalWeight < min)
			{
				min = paths[j].totalWeight;
				minIndex = j;
			}
		}
		
		// 将最近的顶点设为已访问
		flags[minIndex] = true;
		// 基于当前顶点,查找更远顶点的最短路径
		for (int j = 0; j < graph.Count; j++)
		{
			// 把min放在右侧防止溢出
			if (!flags[j] && graph.Matrix[minIndex, j] < paths[j].totalWeight - min)
			{
				paths[j].preNode = minIndex;
				paths[j].totalWeight = min + graph.Matrix[minIndex, j];
			}
		}
	}

	return paths;
}

/// <summary>
/// 输出最短路径
/// </summary>
/// <param name="graph"></param>
/// <param name="startIndex"></param>
/// <param name="endIndex"></param>
private void PrintShortestPathByDijkstra<T>(GraphByAdjacencyMatrix<T> graph,int startIndex,int endIndex)
{
	var paths = Dijkstra<T>(graph, startIndex);
	var stack = new Stack<T>(graph.Count);
	int curIndex = endIndex;
	
	while (curIndex != startIndex)
	{
		stack.Push(graph.Nodes[curIndex]);
		curIndex = paths[curIndex].preNode;
	}
	stack.Push(graph.Nodes[startIndex]);
	while (stack.Count > 0)
	{
		Console.Write(stack.Pop());
		if(stack.Count != 0)
			Console.Write("->");
	}
	
	Console.Write(" 路径长度="+paths[endIndex].totalWeight);
}

代码部分也与Prim算法的代码高度相似。引用一位知乎大佬的话来说,Prim算法更新的是未标记集合到已标记集合之间的距离;而Dijkstra算法更新的是原点到未标记集合之间的距离。

二、Floyd算法

与Dijkstra算法相比,Floyd算法就显得比较“暴力”了。我们来看下面这张图

假设我们要求从A到B的最短路径。首先最直观的路径就是A直接到B:A->B = 9。但假如我们找一个中间节点,也就是C,就会发现A->C->B = 7要比A->B = 9更短。因此现在A到B的最短路径更新为:A->C->B = 7。

接下来看C点。C到B的直连路径为:C->B = 3。但是如果找中间节点D,就会发现C->D->B = 2比C->B = 3更短。因此C到B的最短路径更新为:C->D->B = 2。

最终,A到B的最短路径就是:A->C->D->B = 6。

这就是Floyd算法的核心思想。

下面来通过一个具体的例子讲解算法流程。首先需要准备两个二维数组,weights数组用来存储各顶点之间的路径长度,paths数组用来存储路径的中间节点。在初始状态下,weights数组初始化为与图的邻接矩阵一致,paths数组初始化为路径的尾结点(如A->B的中间节点设置为B)。

首先,以A节点为中间节点,计算其他两个顶点经过A点相连的路径和,并与直连的路径相比较。如果经过A节点的方案更短,则更新到这两个矩阵中。比如B->C = 5,如果经过A节点则B->A->C = 7,路径变长了,所以不需要更新。又如C->D = ∞,如果经过A节点,则C->A->D = 3,路径变短了,所以需要更新。

接下来再以B为中间节点进行计算。

以此类推,直到整个矩阵全部更新完。最终的结果如下

现在假如我们要找A到E的最短路径。从weights数组可得A到E的最短路径长度为7。然后根据paths求得具体路径。首先根据paths[0][4] = 3可知,从A到E需要经过D点,也就是A->D。然后再根据paths[3][4] = 1可知,从D到E需要先经过B点,即A->D->B。再根据paths[1][4] = 4可知,从B到E可以直达,即A->D->B->E。

代码如下

/// <summary>
/// Floyd算法
/// </summary>
/// <param name="graph"></param>
public Path[,] Floyd<T>(GraphByAdjacencyMatrix<T> graph)
{
	// 这里可以复用前面的Path结构体
	Path[,] paths = new Path[graph.Count,graph.Count];
	
	// 将路径长度初始化为与邻接矩阵一致
	// 将路径中间点初始化为边的尾结点
	for (int i = 0; i < graph.Count; i++)
	{
		for (int j = 0; j < graph.Count; j++)
		{
			paths[i, j].totalWeight = graph.Matrix[i, j];
			paths[i, j].preNode = j;
		}
	}

	// 依次寻找经过中间节点小于直达的路径
	for (int nodeIndex = 0; nodeIndex < graph.Count; nodeIndex++)
	{
		for (int row = 0; row < graph.Count; row++)
		{
			for (int col = 0; col < graph.Count; col++)
			{
				// 求和转换为求差防止溢出
				if (paths[row, col].totalWeight - paths[nodeIndex,col].totalWeight > paths[row,nodeIndex].totalWeight )
				{
					paths[row, col].totalWeight =
						paths[row, nodeIndex].totalWeight + paths[nodeIndex, col].totalWeight;
					paths[row, col].preNode = nodeIndex;
				}
			}
		}
	}
	return paths;
}

/// <summary>
/// 输出最短路径
/// </summary>
/// <param name="graph"></param>
/// <param name="startIndex"></param>
/// <param name="endIndex"></param>
private void PrintShortestPathByFloyd<T>(GraphByAdjacencyMatrix<T> graph,int startIndex,int endIndex)
{
	var paths = Floyd<T>(graph);
	int curIndex = startIndex;
	
	while (curIndex != endIndex)
	{
		Console.Write(graph.Nodes[curIndex]+"->");
		curIndex = paths[curIndex, endIndex].preNode;
	}
	Console.Write(graph.Nodes[endIndex]);
	Console.Write(" 路径长度="+paths[startIndex,endIndex].totalWeight);
}

三、参考资料

[1].《大话数据结构》
[2]. https://zhuanlan.zhihu.com/p/87748517
[3]. https://zhuanlan.zhihu.com/p/72248451

数据结构知识整理16最短路径 最短路径 在一个无权图中,从一个顶点到另一个顶点可能存在多条路径,路径长度不同,把路径长度最短(即经过边数最少)的那条路径称为最短路径,其路径长度叫做最短路径长度或最短距离。对于有权图,应考虑路径上各边的权值,则通常把一条路径上所经过边的权值之和定义为该路径的路径长度或称带权路径长度。从源点到终点可能不止一条路径,把带权路径长度最短的那条路径称为最短路径,其路径长度(权值之和)称为最短路径长度或... 阅读详情

相关推荐

详解BFS,Dijkstra算法,Floyd算法是如何解决最短路径问题的

目录1.BFS算法2.Dijkstra算法3.Floyd算法4.总结G纲是个物流离散中心,经常需要往各个城市运东西,怎么运送距离最近——单源最短路径问题各个城市之间也学要来往,相互之间怎么走距离最近?——每对顶点之间的最短路径如下图,BFS算法是如何实现最短路径问题的呢?设从顶点2开始,第一次搜索的结点为1号结点和6号结点,路径为1,从1号结点和6号结点开始找相邻的接地,5号结点和3号7号为相邻的结点,然后5号结点周围都是已经访问过的,3号结点和7号结点分别搜索搭配4号和8号结点,路径为4 代码 B

莫浅子的博客 1万+

最短路径问题—Dijkstra算法和Floyd算法

最短路径问题一般分为两类:一是单源最短路径,即求图中某一顶点到其他顶点的最短路径,可通过Dijkstra(迪杰斯特拉)算法求解;二是求每一对顶点间的最短路径,可通过Floyd( 弗洛伊德)算法求解。

24考研人晴落的博客 5182

数据结构之——最短路径(Dijkstra算法和Floyd算法)

最短路径是图论中一个很经典的问题:给定图G(V,E),求一条从起点到终点的路径,使的这条路径上经过的所有边的边权之和最小。 1.Dijkstra算法 Dijkstra算法(迪杰斯特拉)用来解决单源最短路径问题,即给定图G和起点s,通过算法得到s到达其他顶点的最短距离。Dijkstra的基本思想是对图G(V,E)设置集合S,存放已被访问的顶点,然后每次从集合V-S中选择与起点s的最短距离最小的一个顶点(记为u),访问并加入集合S,之后,令顶点u为中介点,优化起点s与所有从u能到达的顶点v之间的最短距离,这样的

xiaoyong5854的博客 3689

Dijkstra算法和Floyd算法详解(MATLAB代码)

详细讲解Dijkstra算法和Floyd算法+MATLAB代码

lihaiyuan_0324的博客 5442

图-最短路径—Dijkstra算法和Floyd算法

一、Dijkstra算法 1.定义概览:单源最短路径算法 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算...

凌凌小博客 2002

最短路径 —— Dijkstra 算法和 Floyd 算法

Dijkstra 算法 求某一顶点到其余各顶点的最短路径 设有两个顶点集合 S 和 U,集合 S 中存放图中已找到最短路径的顶点,集合 U 存放图中剩余顶点。初始状态时,集合 S 中只包含源点 v0,然后不断从集合 U 中选取到顶点 v0v_0v0​ 路径长度最短的顶点 vuv_uvu​ 并入集合 S 中。集合 S 每并入一个新的顶点 vuv_uvu​ ,都要修改顶点 v0v_0v0​ 到集合 ...

starter_____的博客 995

最短路径——Dijkstra算法与Floyd算法

本文介绍图论中求最短路径的Dijkstra算法和Floyd算法,并给出了C语言代码实现。

仅以此博客记录日常学习工作中所思所得,水平有限,难登大雅,万望海涵。 2554

BCM-BCP-DRP-运维管理之故障管理——故障的分类与处理流程

ITSM Business Continuity Manage(BCM) BusinessContinuityPlan(BCP) 偏业务 DisasterRecoveryPlan(DRP) 偏IT 天塌了,考虑在天塌了的状态下做什么,怎么开展业务就是BCP; 天塌了,考虑怎么把天撑回去,就是DRP。 DRP+BCP+供应链管理+危机管理等就是BCM (业务连续性管...

mmgithub123的博客 2716

图的应用——最短路径(Dijkstra 算法和 Floyd 算法)

参照2025年王道的数据结构考研复习指导书对Dijkstra算法求单源最短路径问题和Floyd算法求各顶点之间最短路径问题的过程进行了详细的介绍。

kusunoki的博客 7775

别再硬编码了!Flowable工作流动态审批人配置全解析(Spring Boot集成版)

本文深入解析Flowable工作流在Spring Boot中的动态审批人配置技术,通过角色、部门等变量实现审批流程的灵活设计。文章详细介绍了架构原理、前端配置映射、动态候选组解析及查询优化方案,帮助企业提升审批流程的适应性和维护效率。

weixin_30919571的博客 129

UFS逻辑单元管理

介绍UFS 逻辑单元管理和配置

m0_51720747的博客 1932

最短路径算法:Dijkstra与Floyd

本文介绍了两种经典的最短路径算法:Dijkstra算法和Floyd算法。Dijkstra算法适用于单源最短路径问题,采用贪心策略,时间复杂度为O((V+E)logV),但不能处理负权边。Floyd算法则计算所有顶点对间的最短路径,采用动态规划方法,时间复杂度为O(V³),可处理负权边但不支持负权环。文章通过代码示例、流程图和对比表格详细说明了两种算法的原理、实现和适用场景,帮助读者根据实际问题需求选择合适的算法解决方案。最后建议读者动手实践以加深理解。

从不水文,坚持创作,加油 1535

RDMA学习笔记-IB五层网络协议和报文结构

Reference InfiniBand Architecture Specification Volume 1, Release 1.3 文章目录IBA 网络协议分层1.链路层1.1 LRH1.2 ICRC1.3 VCRC2.网络层(GRH)3.传输层3.1 BTH3.2 extended transport header4. 报文结构4.1 send request4.2 RDMA Write request4.3 RDMA Read request4.4 ACK4.5 Atomic operatio

u014114310的博客 9459

最短路径问题(Dijkstra算法、Floyd算法)

最短路径问题(Dijkstra算法、Floyd算法) 将近一天的时间(其实中间大部分看手机去了)终于把最短路径这个经典问题算搞懂了吧 一、Dijkstra算法 简单介绍: Dijkstra算法(即迪杰斯特拉算法)时间复杂度(O(n^2))主要就是解决从单一源点到其他各点的最短路径问题; 基本思路: 设置两个顶点的集合:S和T(S+T=V)(也就是说S和T集合的元素个数的和为:总结点个数),集合...

serendipity的博客 2823

ubuntu20.4源码安装最新gcc(gcc V12.2)

Ubuntu20.4自带的gcc为V9.4.0的版本,老版本的gcc存在不支持新版本C语言规范,在配置、编译、安装应用软件或工具时,可能存在不能正确安装的问题。(比如:libpqxx-7.7.4在配置时要求c++17版本的支持,但gcc V9.4.0版本不支持c++17)。因此本文介绍ubuntu20.4的系统下载最新gcc12.2版本源码,并进行本地编译、安装。本节内容包括gcc12.2的必备库安装和gcc12.2安装两部分内容组成。

q544344318的博客 1万+

PaddleOCR实战:给图片‘加个框’,轻松搞定小图和长图文字识别不准的难题

本文探讨了PaddleOCR在处理小图和长图时识别精度下降的问题,并提出通过图像边框预处理技术显著提升OCR识别效果。详细介绍了使用OpenCV实现智能边框添加的方法,包括核心原理、工程实践中的关键细节以及性能优化策略,帮助开发者轻松解决非常规尺寸图像的文本检测难题。

weixin_29313547的博客 185

最短路径——Dijkstra算法和Floyd算法

一、Dijkstra算法 1、单源点的最短路径问题:给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。 我们用一个例子来具体说明迪杰斯特拉算法的流程。 定义源点为 0,dist[i]为源点 0 到顶点 i 的最短路径。其过程描述如下: 步骤 dist[1] dist[2] dist[3] dist[4] 已找到的集合 第 1 步 8 ...

凌晨的咸鱼的博客 4万+

声纹识别实战:用Python从零搭建一个简易声纹验证系统(附完整代码)

本文是一份详细的声纹识别实战指南,教你使用Python从零搭建一个简易的声纹验证系统。文章涵盖了从音频采集、预处理、MFCC特征提取,到基于高斯混合模型(GMM)的建模与验证全流程,并提供了完整的代码实现,帮助开发者快速掌握这项生物特征识别核心技术。

ik6789012的博客 228

图的最短路径的Dijkstra算法及Floyd算法

文章目录

薛定谔的猫的博客 1490

《C/C++等级考试(1~8级)历届真题解析》专栏总目录

中国电子学会《全国青少年软件编程等级考试》C/C++编程(1~8级)历届真题解析。订阅后可阅读专栏内所有真题解析,真题持续更新中!

人生就是一个不断学习的过程 2万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

最短路径——Floyd算法与Dijkstra算法

Floyd算法,也被叫做插点法,可以解决多源最短路径的问题,即通过在两个目标点之间插入第三个点作为中转点,从而达到缩短目标点之间距离的目的 (利用《啊哈!算法》一书中的图片更有助于理解 箭头标记的数字为两点之间的距离,我们可以发现通过某个点可以是另外两个点之间的距离减小,且不影响它们之间的连通性 我们用一个二维数组map[I][j]存储上图,i,j任意两点的序号,map[I][j]的值为这两点间...

老豪仔 441

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

最短路径—Dijkstra算法和Floyd算法

Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。 问题描述:在无向图 G=(V,E) 中,假...

CSDN131137的博客 497

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

两种最短路径(测地距离)的算法——Dijkstra和Floyd

     从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。 最短路径问题是图论研究中的一个经典算法问题,旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。算法具体的形式包括: (1)确定起点的最短路径问题- 即已知起始结点,求最短路径...

zod的博客 2万+

【数据结构】最短路径:Dijkstra 与 Floyd 算法(C语言)

在图论的世界中,寻找“最短路径”是一个永恒的经典问题。无论是在 GPS 导航、网络路由还是项目管理中,我们都渴望找到最优解。本文将从最基本概念出发,深入解析两种核心的最短路径算法:Dijkstra和 Floyd-Warshall。

2401_85872527的博客 1500

最短路径:Dijkstra算法和Floyd算法

一、Dijkstra算法(单个顶点到其他顶点的最短距离) 定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单

cristianoxm的博客 1290
上一篇: UGUI性能优化学习笔记(番外)一些零星的优化点
下一篇: Unity Animancer插件(一)基本使用
夜槿笙歌
博客等级 码龄8年 173粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值