Dijkstra是典型最短路径算法,计算一个起始节点到路径中其他所有节点的最短路径的算法和思想。在一些专业课程中如数据结构,图论,运筹学等都有介绍。其思想是一种基础的求最短路径的算法,通过基础思想的变化可以解决很多复杂问题,如导航线路,动态规划等。

Dijkstra 算法思想介绍

如下图是一个多节点,多路径图。下面以该图为例子讲解dijkstra算法寻找最短路径的过程。

以A点为起始点,求A点到其他点 B C D E F 5个点的最短路径,最后得出A到其他点的最短路径。

因为要求A到其他5个点的最短距离,所以构造一个数组记录A到B C D E F 5个点的路径距离。约定:

  • 如果A能够直接达到节点,则使用路径长度即权值作为其距离
  • 如果A节点不能直接达到节点则使用无穷大表示A到该点距离。
  • 任何点到自身都为0

那么在最开始时,A点到图中所有点的距离数组如下:

A B C D E F
0 10 无穷大 4 无穷大 无穷大

dijkstra的算法思想是从以上最短距离数组中每次选择一个最近的点,将其作为下一个点,然后重新计算从起始点经过该点到其他所有点的距离,更新最短距离数据。已经选取过的点就是确定了最短路径的点,不再参与下一次计算。

可能看到这里你完全不明白dijkstra算法的思想,心里可能想:这是说的人话吗?不要紧,如果算法一句话就能解释清楚,那就不会出现那么多算法书了。下面我们就从实际的选取过程中理解这个思想的精髓。

第一次选取

构建好的数组是这样的:

A B C D E F
0 10 无穷大 4 无穷大 无穷大

第一步选取该最短路径数组中值最小的一个点。因为A点到本身不需要参与运算,所以从剩下的点中选择最短的一个是D。

第二步以A-D的距离为最近距离更新A点到所有点的距离。即相当于A点经过D点,计算A到其他点的距离。

A-A : 0

A-B : A-D-B:6

A-C : A-D-C:19

A-D : A-D:4

A-E : A-D-E:10

A-F : A-D-F:去穷大

A B C D E F
0 6 19 4 10 无穷大

将现在A到各个点的距离和之前的比较,到相同点取最小值。更新了B C E的距离,得到如下新的最短距离数组:

A B C D E F
0 6 19 4 10 无穷大

同时现在A D两点已经计算过,不参与下面的计算。

第二次选取

第二次选取的数组为第一次中更新过最短距离的数组

A B C D E F
0 6 19 4 10 无穷大

第一步:因为A D 不参与选取,所有从剩下的点中选取最近距离是点B

第二步:以B为最新点,更新最短数组

A-A : 0

A-B : A-D-B:6

A-C : A-D-B-C:14

A-D : A-D:4

A-E : A-D-B-E:12

A-F : A-D-B-F:无穷大

A B C D E F
0 6 14 4 12 无穷大

对比现在的最短距离和上一个数组的距离,到相同节点取最小的,C点由19更新成14,E点走A-D-E为10,距离更短所以不更新(敲黑板,这个重要),得到如下数组:

A B C D E F
0 6 14 4 10 无穷大

此时B点加入最短路径范围中。

第三次选取

上一步得到的数组为:

A B C D E F
0 6 14 4 10 无穷大

第一步:选取除了A B D节点之外的剩余节点中最短节点,为点E

第二步:以E点为最新节点,更新最短路径数组



因为在上一部中计算达到E点的距离时没有更新距离,A-D-E 为10 最短,所以更新E点到B C F点的距离时走的路径是A-D-E。注意这里的最短距离有对应的路径,选择最小值就是选择最短距离。

A-A : 0

A-B : A-D-B:6

A-C : A-D-E-C:11

A-D : A-D:4

A-E : A-D-E:10

A-F : A-D-E-F:22

A B C D E F
0 6 11 4 10 22

对比现在的最短距离和上一个数组的距离,到相同节点取最小的,更新C点走A-D-E-C 为11,比之前的A-D-B-C14距离更近,更新到F点距离,得到如下数组:

A B C D E F
0 6 11 4 10 22

此时E点加入最短路径范围中。

第四次选取

A B C D E F
0 6 11 4 10 22

第一步:选取除了A B D E节点之外的剩余节点中最短节点,为点C

第二步:以C点为最新节点,更新最短路径数组

A-A : 0

A-B : A-D-B:6

A-C : A-D-E-C:11

A-D : 4

A-E : A-D-E:10

A-F : A-D-E-C-F:16

A B C D E F
0 6 11 4 10 16

对比现在的最短距离和上一个数组的距离,到相同节点取最小的,更新到F点距离,可以得到如下数组:

A B C D E F
0 6 11 4 10 16

第五次选取

A B C D E F
0 6 11 4 10 16

第一步:选取除了A B C D E节点之外的剩余节点中最短节点,也就是最后一个节点:F

第二步:以F点为最新节点,更新最短路径数组。由于F点是最后一个点,所以也不用更新数组,目前的数组就是所求数组

将F点加入最短路径范围中,此时所有的点都加入了最短路径范围,也就是说A点到所有点的距离都找到了。最总得出的距离值为:

最终得到的结果为:

A B C D E F
0 6 11 4 10 16

最终结果

相应的A点到所有点的最短路径走法最终得到的结果为:

A B C D E F
0 6 11 4 10 16

A-A:0

A-B : A-D-B:6

A-C : A-D-E-C:11

A-D:4

A-E:A-D-E:10

A-F:A-D-E-C-F:16

算法总结

Dijkstra算法作为求最短路径的经典算法,个人理解为算法提供了一种思想,每走一步都是找到最短的路径,并且每走一步都实时更新所有距离,保证每次都选择最短路径。

python实现Dijkstra

将以上的过程使用python来实现。

首先总结一个Dijkstra算法的核心思想,分成两步走:

  1. 构造一个最短路径数组,每次找到数组中未访问的节点里最小的点
  2. 以上一步的节点为最新节点,更新起始点到所有点的距离

使用python就是实现这两步即可

数据准备

二维矩阵

如何描述一个图呢?通常有两种方式,分别是:十字链表和二维矩阵。因为二维矩阵更加直观,所以选择二维矩阵。

将上面的图描述成一个二维矩阵



无穷大使用MAX = float('inf')表示,该数值是python中表示无穷大的一个值。



这个二维矩阵真正直观之处在哪里呢?是能够看到任意一个点到其他点的距离。如想看D点到其他点的距离,就是:



在我们的算法两步走中第二步要更新A点经过某点到其他点的距离,正是使用了这个特征。

MAX= float('inf')

matrix = [
[0,10,MAX,4,MAX,MAX],
[10,0,8,2,6,MAX],
[MAX,8,10,15,1,5],
[4,2,15,0,6,MAX],
[MAX,6,1,6,0,12],
[MAX,MAX,5,MAX,12,0]
]

最短路径数组

在上面讲解算法过程中有一个重要的的最短路径数组,不断更新该数组直到所有的点都被访问到。使用python语言,构造该数组:

distance = [MAX] * len(matrix)

len(matrix) 实际上算出的图的点的个数。初始化时所有的节点都是不可达。

在算法过程中还有一个重要的数组,并没有体现出来,但是在python计算时也很重要,那就是访问过的点。每一次访问之后就要将访问过的点加入到该数组中,这样做是为了避免重复访问。

used_node = [False] * len(matrix)

初始化时认为所有点都没有访问到

代码实现



MAX= float('inf')

matrix = [
[0,10,MAX,4,MAX,MAX],
[10,0,8,2,6,MAX],
[MAX,8,10,15,1,5],
[4,2,15,0,6,MAX],
[MAX,6,1,6,0,12],
[MAX,MAX,5,MAX,12,0]
] def dijkstra(matrix, start_node): #矩阵一维数组的长度,即节点的个数
matrix_length = len(matrix) #访问过的节点数组
used_node = [False] * matrix_length #最短路径距离数组
distance = [MAX] * matrix_length #初始化,将起始节点的最短路径修改成0
distance[start_node] = 0 #将访问节点中未访问的个数作为循环值,其实也可以用个点长度代替。
while used_node.count(False):
min_value = float('inf')
min_value_index = 999 #在最短路径节点中找到最小值,已经访问过的不在参与循环。
#得到最小值下标,每循环一次肯定有一个最小值
for index in range(matrix_length):
if not used_node[index] and distance[index] < min_value:
min_value = distance[index]
min_value_index = index #将访问节点数组对应的值修改成True,标志其已经访问过了
used_node[min_value_index] = True #更新distance数组。
#以B点为例:distance[x] 起始点达到B点的距离,
#distance[min_value_index] + matrix[min_value_index][index] 是起始点经过某点达到B点的距离,比较两个值,取较小的那个。
for index in range(matrix_length):
distance[index] = min(distance[index], distance[min_value_index] + matrix[min_value_index][index]) return distance start_node = int(input('请输入起始节点:'))
result = dijkstra(matrix,start_node)
print('起始节点到其他点距离:%s' % result)

结果:

请输入起始节点:0
起始节点到其他点距离:[0, 6, 11, 4, 10, 16]

简单总结

学习python实现Dijkstra重要的地方有几点:

  1. 数据构造 二维矩阵表示图
  2. 图的访问方式 更新最短路径数组的过程无非就是分别比较二维矩阵数组中某一行的值和最短路径数组的值

熟悉这样的处理方式,再有类似的算法也能找到解决的思路。例如一个二维矩阵,从起始点开始只能走向下的相邻的元素,求达到某点的最短路径。

希望通过该篇文章,能够深刻理解Dijkstra算法,做到心中有数,手中有活。如果觉得写的清晰,帮忙点亮大拇指!

一篇文章讲透Dijkstra最短路径算法的更多相关文章

  1. Java邻接表表示加权有向图,附dijkstra最短路径算法

    从A到B,有多条路线,要找出最短路线,应该用哪种数据结构来存储这些数据. 这不是显然的考查图论的相关知识了么, 1.图的两种表示方式: 邻接矩阵:二维数组搞定. 邻接表:Map<Vertext, ...

  2. 练习 Dijkstra 最短路径算法。

    练习 Dijkstra 最短路径算法. #coding: utf-8 # Author: woodfox, Oct 14, 2014 # http://en.wikipedia.org/wiki/Di ...

  3. 数据结构(c++)(第二版) Dijkstra最短路径算法 教学示范代码出现重大问题!

    前言 去年在数据结构(c++)的Dijkstra教学算法案例中,发现了一个 bug 导致算法不能正常的运行,出错代码只是4行的for循环迭代代码. 看到那里就觉得有问题,但书中只给了关键代码的部分,其 ...

  4. Dijkstra最短路径算法[贪心]

    Dijkstra算法的标记和结构与prim算法的用法十分相似.它们两者都会从余下顶点的优先队列中选择下一个顶点来构造一颗扩展树.但千万不要把它们混淆了.它们解决的是不同的问题,因此,所操作的优先级也是 ...

  5. Python 图_系列之纵横对比 Bellman-Ford 和 Dijkstra 最短路径算法

    1. 前言 因无向.无加权图的任意顶点之间的最短路径由顶点之间的边数决定,可以直接使用原始定义的广度优先搜索算法查找. 但是,无论是有向.还是无向,只要是加权图,最短路径长度的定义是:起点到终点之间所 ...

  6. 一篇文章讲明白vue3的script setup,拥抱组合式API!

    引言 vue3除了Composition API是一个亮点之外,尤大大又给我们带来了一个全新的玩意 -- script setup,对于setup大家相信都不陌生,而对于script setup有些同 ...

  7. Dijkstra 最短路径算法 秒懂详解

    想必大家一定会Floyd了吧,Floyd只要暴力的三个for就可以出来,代码好背,也好理解,但缺点就是时间复杂度高是O(n³). 于是今天就给大家带来一种时间复杂度是O(n²),的算法:Dijkstr ...

  8. Dijkstra最短路径算法实例

    #include <stdio.h>#include <stdlib.h>/* Dijkstra算法 */#define VNUM 5#define MV 65536int P ...

  9. 关于Dijkstra最短路径算法

    Dijkstra算法,不是很明白,今天找了一些博客看了一下,决定自己也写一个为以后忘记的时候可以看做准备. 实际上,如果理解没错的话,该算法实际上和枚举法有点像,只不过,在选取出发路径的路径都是最短路 ...

随机推荐

  1. Linux下使用Rsync进行文件同步

    数据备份方案 1.需要备份的文件目录有(原则上,只要运维人员写入或更改的数据都需要备份)./data,/etc/rc.local,/var/spool/cron/root等,根据不同都服务器做不同的调 ...

  2. socket编程之并发回射服务器2

    承接上文:socket编程之并发回射服务器 为了让服务器进程的终止一经发生,客户端就能检测到,客户端需要能够同时处理两个描述符:套接字和用户输入. 可以使用select达到这一目的: void str ...

  3. msf的rpc和json-rpc,我该选择哪个?

    msf的rpc有两种调用方式,那么我们应该调用哪一个呢? 其中restful接口暂且不谈,这个rest api其实是简单对接了一下msf的后端数据库,这个自己也能读数据库来做,这个以后有时间再谈 首先 ...

  4. C. Anton and Fairy Tale(数学推式子)

    \(数学题,式子并不难推,但边界是真的烦\) \(\color{Red}{Ⅰ.其实可以发现,当m>=n时,每次都可以粮食补到n,所以一定是在第n天消耗完毕}\) \(\color{Purple} ...

  5. Linux目录、文件的管理

    centos目录结构 ls / 查看根目录下有哪些文件或者目录 bin 可执行文件的目录 sbin 存放root用户可执行文件目录 etc 配置文件 boot 引导文件 home 普通用户宿主目录 l ...

  6. 王颖奇 201771010129《面向对象程序设计(java)》第四周学习总结

    实验四 类与对象的定义及使用 实验时间 2018-9-20 1.目的与要求 学习目标 掌握类与对象的基础概念,理解类与对象的关系: 掌握对象与对象变量的关系: 掌握预定义类的基本使用方法,熟悉Math ...

  7. Exception in thread "main" java.lang.NoSuchMethodError: scala.Predef$.wrapRefArray([Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray

    我是在用akka框架做简单的一个聊天,然而出师不利,刚开始学就遇到这个问题 遇事不决问百度,百度给出的结果是spark中scala版本和你使用的scala的版本不一致,所导致的错误 我用的是akka, ...

  8. [hdu5253] 最小生成树,Kruskal

    题意:有n*m个单位的农田,给定每个单位农田地势高低,现在需要灌溉所有农田,如果把水引入相邻的农田里需要的管道长度为两者的高度差.求最少的管道长度花费. 思路:比较明显的最小生成树问题,相邻两点之间连 ...

  9. iview input 禁止输入特殊字符 ,解决中文输入法中input把拼音输入

    tips:解决了e.target中输入中文 会把拼音也输入的情况 1 html <FormItem label="角色名称" prop="roleName" ...

  10. JS理论--正则表达式RegExp的创建、元字符、优先度、方法(test(),exec(),match(),replace())

    实战,参数可以对照上面的,代码一定要敲 var str = 'abc123cba456aaa789'; var reg = /\d+/g; console.log(reg.test(str)) //s ...