百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

第六章图-第四节4:最短路径之迪杰斯特拉算法

liebian365 2025-03-04 13:00 17 浏览 0 评论

最短路径shortestpath):主要有以下两类最短路径问题

单源最短路径问题:一个顶点到其他顶点的最短路径

  • 迪杰斯特拉算法(dijkstra)(带权图、无权图)-本节讲解
  • BFS算法(无权图)–点击跳转

各顶点间最短路径问题:也就是每一对顶点间最短路径

  • 弗洛伊德算法-点击跳转

最短路径在通信、交通等领域有重要应用


一:BFS算法局限性

BFS算法只适用于无权图单源最短路径,对于有权图来说则不适用,比如下面“G港”到“R城”相对于用BFS算法找出的10来说还有一条更短的7

二:迪杰斯特拉(dijkstra)算法基本思想

迪杰斯特拉算法:该算法和普利姆算法有些地方比较相似。该算法在剩余顶点中选出一个顶点,通往这个顶点的路径在通往所有顶点的路径中长度是最短的

迪杰斯特拉(dijkstra)算法不便于用语言完整描述,可以跟随下面的例子体会一下这个过程。其中会涉及三个数组

  • dist[]:数组存储了当前起点到其余顶点最短路径的长度path[]:数组存储了起点到其余顶点的最短路径(通过查询该数组,可获得路径信息)
    final[]:数组中标记为1表示被选入最短路径

开始时,各数组初始化如下,其中v_{0}v0有到v_{1}v1的直接路径10、v_{0}v0?有到v_{4}v4?的直接路径5

  • 因此path[1]=0,表示v_{0}v0?有到v_{1}v1?直接路径,其路径长度为dist[1]=10
  • 因此path[4]=0,表示v_{0}v0?有到v_{4}v4?直接路径,其路径长度为dist[4]=5
  • final[0]=true表示此时v_{0}v0?已经被选入最短路径了
  • 由于目前v_{0}v0?到v_{2}v2?没有路径,因此dist[2]=\infin∞


接着,
循环遍历所有顶点,找到还没有确定的最短路径、且dist最小的顶点v_{i}vi?,然后final[ii]=true

  • 因此选择v_{4}v4?


在没有加入v_{4}v4?时,那么v_{0}v0?由于没有路径所以无法到达其中某些顶点,但是当v_{4}v4?加入之后情况有所改变,比如之前v_{0}v0?到v_{3}v3?是没有路径的,但是v_{4}v4?加入后,就有一个路径:v_{0}v0?->v_{4}v4?->v_{3}v3?

所以我们需要对比,若final值为false,更新对应的dist和path信息

  • 对于v_{1}v1?:之前v_{0}v0?->v_{1}v1?为10,但是现在:v_{0}v0?->v_{4}v4?->v_{1}v1?路径之和为8,这是一条更短的路径,因此将dist[1]改为8,将path[1]改为4
  • 对于v_{2}v2?:之前v_{0}v0?->v_{2}v2?为\infin∞,但是现在:v_{0}v0?->v_{4}v4?->v_{2}v2?路径之和为14,这是一条更短的路径,因此将dist[2]改为14,将path[2]改为4
  • 对于v_{3}v3?:之前v_{0}v0?->v_{3}v3?为\infin∞,但是现在:v_{0}v0?->v_{4}v4?->v_{3}v3?路径之和为7,这是一条更短的路径,因此将dist[3]改为7,将path[3]改为4

上面结束了第一轮,总的来说两个步骤:

  • 先在dist数组中找到一个最小的值,通往这个顶点的路径在通往其它顶点的路径中长度是最短的。换句话说如果你不能保证它是最小的,那就别提后面的了
  • 接着由于该顶点的假如,使得前后情况有所变化,之前A到C没有路径,但是B加入之后,存在了一个路径A->B->C,所以我们要判断刚并入路径中的顶点是否会产生一些潜在的路径

第2轮



第3轮


第4轮,算法结束

三:迪杰斯特拉(dijkstra)算法代码实现

王道视频课并没有介绍迪杰斯特拉(dijkstra)算法的代码实现,但是我认为了解其代码是十分有必要的。上述描述过程看完之后大家可能有这样的感觉就是:“也就那样嘛”,但这只是纸上谈兵


总的来说迪杰斯特拉算法和普利姆算法其实还是挺相似的。普利姆算法第一个小for循环是在找权值最小的边并纳入其中,迪杰斯特拉算法第一个小for循环
也是在剩余顶点中选出一个顶点,通往这个顶点的路径在通往所有顶点的路径中长度是最短的。普利姆算法第二个小for循环是在更新lowcost数组,是指如果剩余的结点距离树的距离小于之前状况就更新,而迪杰斯特拉算法第二个for循环用于判断刚并入路径中的顶点的加入导致是否会出现通往其余顶点更短的路径(他在判断时,是以新加入的那个结点为起点从未被并入的结点中逐个比较

Bash
//带权图
typedef struct
{
	int no;
	char info;
}VertexType;
typedef struct
{
	float edges[maxSize][maxSize];
	int n, e;
	VertexType vex[maxSize];
}MGraph;

void Dijkstra(MGraph g, int v, int dist[], int path[])
/*
	dist[]数组存储了当前起点到其余顶点最短路径的长度
	path[]数组存储了起点到其余顶点的最短路径(通过查询该数组,可获得路径信息)
	final[]数组中标记为1表示被选入最短路径
*/
{
	int final[maxSize];//初始化final数组
	int min, i, h, u;
	for (i = 0; i < g.n; ++i)
	{
		dist[i] = g.edges[v][i];//初始化dist数组,根据edges数组的信息,录入根结点到其余结点距离信息
		final[i] = 0;//开始时所有结点均为被并入,故设为0
		if (g.edges[v][i] < INF)
		/*
		  举例 如果path[0][3]不是无穷大(置于无穷大会大于这个很大的数)
		   那么path[3]=0,表示3这个节点之前是0,0-3是一个最短路径
		*/
			path[i] = v;
		else
			path[i] = -1;//如果path[3]=-1,表示之前没有元素
	}
	final[v] = 1;//根节点被并入
	path[v] = -1;//根节点前没有结点
///////////////迪杰斯特拉算法核心//////////////
	for (i = 0; i < g.n-1; ++i)
	{
		min = INF;
		for (int j = 0; j < g.n; ++j)
		/*
			此for循环每次从剩余结点中选出一个一个结点,通过往这个
			顶点的路径在通往所有剩余顶点的路径中是最短的
		*/
		{
			if (final[j] == 0 && dist[j] < min)
			{
				u = j;
				min = dist[j];
			}
		}
		final[u] = 1;
		for (int j = 0; j < g.n; ++j)
		/*
			此for循环以刚并入的结点作为中间点,对所有通往剩余顶点的路径进行监测
		*/
		{
			if (final[j] == 0 && dist[u] + g.edges[u][j] < dist[j])
			{
				/*
				如果顶点u的加入会出现通往顶点j的更短的路径,那么就更新信息
				*/
				dist[j] = dist[u] + g.edges[u][j];
				path[j] = u;
			}
		}
	}
}

四:迪杰斯特拉(dijkstra)算法代码视频演示

为了使大家能够更好地掌握这个算法,我截取了天勤视频课中关于这一部分的代码视频演示,希望大家可以跟随视频演示走一遍这个代码的流程(代码和天勤视频课一致)


Dijkstra算法代码流程图演示

五:迪杰斯特拉(dijkstra)算法动画演示

六:迪杰斯特拉(dijkstra)算法答题规范

考研数据结构中不太可能让你写迪杰斯特拉(dijkstra)算法的代码,如果真要考察,最有可能的形式就是给出一个图,让你描述迪杰斯特拉(dijkstra)算法求解最小生成树的过程

而这个算法又不太好用语言描述(可以说是越写越乱),所以我推荐的方法是采用表格法,思路不乱而且特别容易描述

如下


表格如下

相关推荐

Linux-常用操作命令介绍(linux常用的命令大全)

1.帮助命令帮助命令1.1help命令语法格式:命令--help作用:查看某个命令的帮助信息示例#ls--help#netstat--help1.2man命令语法格式:man命令...

推荐:一个小而美的Java工具类库(java工具软件)

前言是的,你没看错,没看错,它就是hutool!相信很多做java开发的朋友应该都已经认识并使用过它了,今天带大家再重温一下它都有哪些功能,并以示例来看看hutool是如何简便实现JWT认...

【SpringBoot后端开发】第三部分 Linux操作系统常用命令(3)

创作不易,请帮忙转发、点赞和评论!四、Linux常用命令对于Linux系统来说,中央处理器、内存、磁盘驱动器、键盘、鼠标、用户等都是文件,而Linux系统管理的命令是它正常运行的核心,与之DOS命令类...

linux常用命令在线查询工具(linux常用命令在线查询工具有哪些)

linuxvi编辑器常用命令linux查看iplinuxfind-name查找文件名linuxshelllinux查看端口占用linux删除文件命令linuxcp命令复制文件到另一个...

使用免费绿色工具chfs,将文件夹共享成网盘

需求:业务需求方有个需要将apk包上传到服务器中,通过chfs可以将服务器目录共享出来,可以可以登录后台自行上传apk文件包。本文就教大家三个知识点1.centos7下使用chfs,共享目录。2.使用...

Mysql和Hive之间通过Sqoop进行数据同步

文章回顾理论大数据框架原理简介大数据发展历程及技术选型实践搭建大数据运行环境之一搭建大数据运行环境之二本地MAC环境配置CPU数和内存大小查看CPU数sysctlmachdep.cpu#核数为...

真实案例记录Linux被植入rootkit导致服务器带宽跑满的解决过程

一、关于linux下的rootkitrootkit是Linux平台下最常见的一种木马后门工具,它主要通过替换系统文件来达到攻击和和隐蔽的目的,这种木马比普通木马后门更加危险和隐蔽,普通的检测工...

python周期任务调度工具Schedule使用详解

如果你想周期性地执行某个Python脚本,最出名的选择应该是Crontab脚本,但是Crontab具有以下缺点:不方便执行秒级任务。当需要执行的定时任务有上百个的时候,Crontab的管...

Linux 系统日常巡检脚本(shell巡检脚本)

Linux系统日常巡检脚本,巡检内容包含了,磁盘,内存cpu进程文件更改用户登录等一系列的操作直接用就行了。报告以邮件发送到邮箱在log下生成巡检报告。#!/bin/bash#@Au...

Schedule—简单实用的 Python 周期任务调度工具

如果你想周期性地执行某个Python脚本,最出名的选择应该是Crontab脚本,但是Crontab具有以下缺点:1.不方便执行秒级任务。2.当需要执行的定时任务有上百个的时候,Cronta...

celery定时与异步任务详解(定时任务异步执行)

celery简介Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度。Celery的架构由三部分组成,消息中间件(messagebroke...

开源免费的定时任务管理系统:Gocron

Gocron:精准调度未来,你的全能定时任务管理工具!-精选真开源,释放新价值。概览Gocron是github上一个开源免费的定时任务管理系统。它使用Go语言开发,是一个轻量级定时任务集中调度和管理...

PHP Laravel定时任务Schedule(laravel定时任务原理)

前提:本文方法是利用Linux的crontab定时任务来协助实现Laravel调度(Mac也一样)。一、首先添加Crontab定时任务,这里只做简单介绍:用命令crontab-e添加如下内容**...

Linux的常用命令就是记不住,怎么办?于是推出了这套教程

1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...

如何定期执行 Python 脚本:5 种常见方法

定期执行任务是自动化工作流程中的重要环节,无论是数据抓取、文件备份,还是定期报告生成,定时运行脚本都可以极大提高效率。本文将介绍五种方法,通过这些方法,你可以轻松设置定期执行Python脚本的任务...

取消回复欢迎 发表评论: