最短路径Dijkstra算法的分析与具体实现(思路加代码)

news2024/9/29 17:21:38

❤️作者主页:微凉秋意
✅作者简介:后端领域优质创作者🏆,CSDN内容合伙人🏆,阿里云专家博主🏆
✨精品专栏:C++面向对象
🔥系列专栏:数据结构与课程设计

文章目录

  • 🔥前言
  • Dijkstra 算法分析
    • 初始条件
    • 第一轮
    • 第二轮及以后
  • Dijkstra 代码实现
    • 输入输出格式
    • 时间复杂度


🔥前言

经典的求解最短路径算法有这么几种:广度优先算法Dijkstra算法、Floyd算法,在此专栏中我都会将这些算法的分析与具体实现详细的展现出来。此篇文章是对 Dijkstra算法的总结,该算法适用于带权有向图,可求出起始顶点到其他任意顶点的最小代价以及对应路径。

Dijkstra 算法分析

一般来说,有关图的算法的存储结构为邻接表、邻接矩阵,这次就以邻接矩阵存储为例,求出下图的最短路径:

在这里插入图片描述

初始条件

需要有三个数组:

  • final[]:布尔型,用来记录顶点是否已找到最短路径
  • dist[]:整形,记录最短路径长度(带权)
  • path[]:整形,记录当前顶点的前驱结点下标
  •   #define MAXVERTEX 6
      bool final[MAXVERTEX];
      int dist[MAXVERTEX];
      int path[MAXVERTEX];
    

对于起始顶点需要将final 设为true,dist 设为 0,path 设为-1

第一轮

遍历所有与起始顶点相连的结点,找到一个权值最小的边,并将对应顶点 i 加入到最短路径,即 final[i] = true,之后再遍历与 i 相邻的顶点,若final 值为false 且dist 值小于dist[i]+dist[i][] 就将其dist 值更新,path 值改为 i。

第二轮及以后

第一轮结束后会有两个顶点的 final 值为 true,实际上最大的循环只需要进行n - 1次,从第一轮结束后我们从值为 false 的顶点中找 dist 值最小的顶点,将其fianl 值设为 true,检查与其相邻顶点的path 值和dist 值可否更新(判断与dist[i]+dist[i][]的大小),重复第二轮的操作直至大循环结束。这样最终的 dist 存放的就是起始顶点到对应下标顶点的最短路径长度,而path 存放的就是最短路径。

Dijkstra 代码实现

#include<iostream>
using namespace std;
// 模拟实现Dijkstra算法,不适用于存在负值的带权图
#define MAXVERTEX 6
typedef struct {
	char Vertex[MAXVERTEX]; //顶点集
	int Edge[MAXVERTEX][MAXVERTEX]; // 存放权值
	int vernum, arcnum; // 顶点数和边数
}MGraph;

// 初始化图
void InitGraph(MGraph& G) {
	G.Vertex[0] = 'A';
	G.Vertex[1] = 'B';
	G.Vertex[2] = 'C';
	G.Vertex[3] = 'D';
	G.Vertex[4] = 'E';
	G.vernum = 5;
	G.arcnum = 10;

	// 图中边权值均设为无穷大
	for (int i = 0; i < G.vernum; i++) {
		for (int j = 0; j < G.vernum; j++) {
			G.Edge[i][j] = INT_MAX;
		}
	}
	// 根据具体图形设置具体权值
	G.Edge[0][1] = 10; // 诸如此类
	G.Edge[0][4] = 5;
	G.Edge[1][2] = 1;
	G.Edge[1][4] = 2;
	G.Edge[4][1] = 3;
	G.Edge[2][3] = 4;
	G.Edge[3][2] = 6;
	G.Edge[4][3] = 2;
	G.Edge[3][0] = 7;
	G.Edge[4][2] = 9;
}
bool final[MAXVERTEX];
int dist[MAXVERTEX];
int path[MAXVERTEX];

void Dijkstra(MGraph G,int v) {
	for (int i = 0; i < G.vernum; i++) {
		final[i] = false;
		dist[i] = G.Edge[v][i];
		path[i] = (G.Edge[v][i] == INT_MAX ? -1 : v);
	}
	final[v] = true;
	dist[v] = 0;
	// 第一轮
	int index =v; // 权值最小的边顶点下标
	int para = INT_MAX;
	for (int j = 0; j < G.vernum; j++) {
		if (final[j] == false && G.Edge[v][j] < para) {
			para = G.Edge[v][j];
			index = j;
		}
	}
	// 第二轮及以后
	for (int i = 0; i < G.vernum; i++) {
		for (int c = 0; c < G.vernum; c++) {
			if (final[c] ==false && G.Edge[index][c] < INT_MAX) {
				if (G.Edge[index][c] + dist[index] < dist[c]) {
					dist[c] = G.Edge[index][c] + dist[index];
					path[c] = index;
				}
			}
		}
		// 找到final 为false的顶点中权值最小的顶点下标
		int temp = INT_MAX;
		int in = v;
		for (int i = 0; i < G.vernum; i++) {
			if (final[i] == false && dist[i] < temp) {
				temp = dist[i];
				in = i;
			}
		}
		index = in; // 更新下标
		final[index] = true;
	}
}

void print_path(MGraph G ,int v) {
	cout << "对应的最短路径为:";
	cout << G.Vertex[v] << "->";
	for (int i = 0; i < G.vernum; i++) {
		if (path[v] != 1) {
			cout << G.Vertex[path[v]] << "->";
			v = path[v];
		}
	}
	cout << G.Vertex[1] << endl;
}

int main() {
	MGraph G;
	InitGraph(G);
	Dijkstra(G, 1);
	cout << "顶点B到顶点D的最小花费为:"<< dist[3] << endl;
	print_path(G, 3);
}


运行结果:
在这里插入图片描述

输入输出格式

想得到哪个顶点的最短路径就在主函数中 Dijkstra(G, ?) 第二个参数写入下标即可,其他对应关系:顶点下标 0~4 对应 A~E,所以在 cout那行代码中dist下标要与到达顶点一致,而出发顶点要与自己填入的下标一致。

print_path 函数里的 if 语句中的下标也要和起始顶点下标一致,最后的一个cout也同样处理

例如:

Dijkstra(G,0);
// dist[2];
cout<<"顶点A到顶点C的最短路径为"<<dist[2]<<endl;
void print_path(MGraph G ,int v) {
	cout << "对应的最短路径为:";
	cout << G.Vertex[v] << "->";
	for (int i = 0; i < G.vernum; i++) {
		if (path[v] != 0) {
			cout << G.Vertex[path[v]] << "->";
			v = path[v];
		}
	}
	cout << G.Vertex[0] << endl;
}

在这里插入图片描述

时间复杂度

Dijkstra 算法的时间复杂度只与顶点有关,可以通过算法分析看出来每次都要对一个顶点遍历寻找与其相邻顶点的最小权值,所以时间复杂度应为: O ( n 2 ) O(n^2) O(n2),也可以写成 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2),V 是顶点的含义(vertex)。


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

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

相关文章

Gson序列化Class对象报错解决办法

1. 背景 昨天在写RPC的基础Demo的时候&#xff0c;使用JSON作为序列化方式&#xff0c;然后在序列化对象的时候&#xff0c;报错了。 我复现一下该报错&#xff1a; public class GsonTest {public static void main(String[] args) {new Gson().toJson(String.class);}}具体…

C/C++每日一练(20230309)

目录 1. 罗马数字转整数 ★ 2. 最大数 ★★ 3. 有效数字 ★★★ &#x1f31f; 每日一练刷题专栏 C/C 每日一练 ​专栏 Python 每日一练 ​专栏 1. 罗马数字转整数 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&…

达梦关系型数据库

达梦关系型数据库一、DM8 安装1. 安装包下载2. Docker 安装3. Linux 安装4. Windows 安装二、DM 管理工具三、命令行交互工具 DIsql四、DM8 SQL使用1. 创建模式2. 创建表3. 修改表4. 读写数据5. 查看库下所有的表名6. 查看表字段信息GitHub: link. 欢迎star国产自主研发的大型…

数据挖掘(2.2)--数据预处理

目录 二、数据描述 1.描述数据中心趋势 1.1平均值和截断均值 1.2加权平均值 1.3中位数&#xff08;Median&#xff09;和众数(Mode) 2.描述数据的分散程度 2.1箱线图 2.2方差和标准差 2.3正态分布 3.数据清洗 3.1数据缺失的处理 3.2数据清洗 二、数据描述 描述数…

自动化测试实战篇(9),jmeter常用断言方法,一文搞懂9种测试字段与JSON断言

Jmeter常用的断言主要有&#xff0c;JSON断言和响应断言这两种方式。 断言主要就是帮助帮助人工进行快速接口信息验证避免繁杂的重复的人工去验证数据 第一种响应断言Apply to&#xff1a;表示应用范围测试字段&#xff1a;针对响应数据进行不同的匹配响应文本响应代码响应信息…

【Go自学第一节】GoLang 数据类型

和Java类型&#xff0c;go拥有多种数据类型&#xff0c;可以把它分为四个大类基础类型、聚合类型、引用类型和接口类型 一、基本数据类型 基本数据类型又可以细分为&#xff1a;数字类型&#xff08;整型、浮点型&#xff09;、布尔类型、字符串类型 整型 Go 的整型分为有符号…

计算机网络的166个概念你知道几个 第十一部分

计算机网络数据链路层和物理层节点&#xff1a;一般指链路层协议中的设备。链路&#xff1a;一般把沿着通信路径连接相邻节点的通信信道称为链路。MAC 协议&#xff1a;媒体访问控制协议&#xff0c;它规定了帧在链路上传输的规则。奇偶校验位&#xff1a;一种差错检测方式&…

基于gin-vue-admin[gin+gorm]手动实现crud(全)

使用Gin-Vue- Admin框架手动实现crud 在gva框架下自己手动实现一个CRUD的操作&#xff0c;该操作将会结合gen进行探讨学习&#xff0c;具体实现可以看下面代码的实现&#xff0c;项目目录层级分为api层&#xff0c;service层&#xff0c;model层&#xff0c;common层&#xff…

1/4、1/2、整车悬架天棚主动控制仿真分析合集

目录 前言 1. 1/4悬架系统 1.1数学模型 1.2仿真分析 2. 1/2悬架系统 2.1数学模型 2.2仿真分析 3. 整车悬架系统 3.1数学模型 3.2仿真分析 4.总结 参考文献 前言 对于天棚控制相比大家不陌生&#xff0c;它是由美国的Karnopp提出&#xff0c;利用假设的与天棚固连…

【数据结构】链表相关题目(简单版)

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; 初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是…

软件测试10

Linux和数据库 1.Linux命令&#xff1a;软件测试第一个任务&#xff0c;一般都需要进行环境搭建&#xff0c;一部分环境搭建内容是在服务器上实现的&#xff0c;跟服务器交互需要使用Linux命令。&#xff08;因为Linux没有图形化页面&#xff09; 2.数据库&#xff1a;所有的软…

ccf-csp 202112-3登机牌条码

题目背景 西西艾弗岛景色优美&#xff0c;游人如织。但是&#xff0c;由于和外界的交通只能靠渡船&#xff0c;交通的不便严重制约了岛上旅游业的发展。西西艾弗岛管委会经过努力&#xff0c;争取到了一笔投资&#xff0c;建设了一个通用航空机场。在三年紧锣密鼓的主体建设后…

Jetpack Compose 中的动态加载、插件化技术探索

在传统的 Android 开发模式中&#xff0c;由于界面过分依赖于 Activity、Fragment这样的组件&#xff0c;一个业务模块中往往会存在着大量的 Activity 类&#xff0c;因此诞生了很多的插件化框架&#xff0c;这些插件化框架基本都是想方设法的使用各种Hook/反射手段来解决使用未…

c++11auto

autoc11中auto并不代表一种实际的数据类型&#xff0c;它只是一个类型声明的占位符&#xff0c;auto也并不是再所有场景下都能推导出变量的实际类型&#xff0c;使用auto不需要进行初始化&#xff0c;让编译器推导出它的实际类型&#xff0c;再编译阶段将auto占位符替换为真正的…

没有比这更详细的-压测工具Jmeter介绍及使用了

一、压测工具选型 1.1、前言 压力测试是每一个Web应用程序上线之前都需要做的一个测试&#xff0c;他可以帮助我们发现系统中的瓶颈问题&#xff0c;减少发布到生产环境后出问题的几率&#xff1b;预估系统的承载能力&#xff0c;使我们能根据其做出一些应对措施。所以压力测…

【Linux基础篇】一、Linux入门基础命令

一、Linux基础命令 1、Linux的目录结构 /&#xff0c;根目录是最顶级的目录了Linux只有一个顶级目录&#xff1a;/路径描述的层次关系同样适用/来表示/home/itheima/a.txt&#xff0c;表示根目录下的home文件夹内有itheima文件夹&#xff0c;内有a.txt 2、ls命令 功能&#…

数字孪生GIS智慧风场Web3D可视化运维系统

随着国家双碳目标的实施&#xff0c;新能源发电方式逐渐代替了污染大气层的火力发电&#xff0c;其中风力发电相比于光伏发电具有能量密度高、发电小时数长、生命周期达20-25年之久等独特的优势。风能取之不尽、用之不竭&#xff0c;在新型能源互联网下&#xff0c;风力发电有可…

三、GC算法垃圾回收器

文章目录&#xff08;持续更新中... ...CMS and G1&#xff09;概述如何判断对象存活引用计数法根可达算法GC算法(垃圾回收算法)分代收集理论标记-清除算法复制算法标记-整理算法垃圾回收器概述Serial收集器Parallel收集器Parallel Old收集器CMS收集器G1收集器常用的收集器组合…

STM32实战项目-串口打印

前言&#xff1a; 本小结主要实现串口打印功能&#xff0c;主要将上一结的状态机运行次数&#xff0c;通过串口在串口终端上打印出来&#xff0c;硬件电路上主要是TTL转USB驱动电路&#xff0c;软件上主要有状态机函数&#xff0c;串口发送函数等调试工具是串口助手。 目录 1…

机器学习学习记录1:假设空间

我们可以把学习过程看作一个在所有假设组成的空间中进行搜索的过程&#xff0c;搜索目标是找到与训练集"匹配" 的假设&#xff0c;即能够将训练集中的瓜判断正确的假设.假设的表示一旦确定&#xff0c;假设空间及其规模大小就确定了.对于西瓜问题&#xff0c;这里我们…