算法与数据结构之Dijkstra算法

Dijkstra算法主要用于计算图中一个起始节点到其他所有节点的最短路径即单源最短路径。它的核心思想基于贪心策略,

Dijkstra算法在最短路径问题求解上已被证明最优,本文将基于几个例子和考研真题来彻底讲明白这一算法的基本运作原理。

基本流程

Dijkstra算法的基本流程如下:

看着很复杂,其实不然。整个算法就是在不断地更新和维护visited,dist,prev这三个数组外加一个顶点集合S,共计执行len(V)次。上述流程结束后,dist数组内是从起点到各个顶点的最短距离 ,prev内记录的是每个顶点在最短路径上的前驱, visited则记录当前节点是否被更新过 ,顶点集合S 记录使用过的顶点****,当每个顶点都位于顶点集合内时算法结束。****

算法执行过程

Dijkstra算法的执行次数取决于图中顶点的个数,算法在每一轮结束后都会选取disti中最小值对应的顶点Vi用于下一轮的更新,更新的过程就是将当前顶点加入到路径中探索局部最短距离。

在算法执行过程中,需要不断更新dist,visited,prev三个数组,这三个数组的更新方式如下:

  1. 对于dist数组,disti的值为本轮所选点加入到路径后到Vi的最短距离。
  2. 对于visited数组,visitedi的值为bool型,用来判断点Vi是否被更新过。
  3. 对于Prev数组,previ的值是点vi在最短路径上的前驱节点。

更一般化,disti的取值为:

previ的取值为:

总而言之,在算法执行的某一轮中,如果加入该轮使用的顶点后总路径长度变短,那么disti更新为加入该点后的路径长度,顶点i的前驱节点previ,如果路径长度没有变短(包括没有变化),那么disti的值不需要更新,顶点i的前驱节点previ仍保持原样为

算法初始化

图1

在算法开始前,需要对三个数组以及顶点集合S进行初始化,初始化的方法如下:

  1. disti为起点到点Vi的可达路径所对应的距离,如果不存在这样的路径那么设为∞。
  2. previ为从起点到该点可达路径上的前一个顶点编号(其实就是起点),如果从起点到该点存在一条直达路径比如V0-V1那么prev1=0,如果不存在这样的路径那么设为-1。
  3. Visitedi表示算法在某一轮结束后点vi是否用于更新路径,初始化时显然只有起点V0被用到,故只有Visited0为True。
  4. S内存放的是每一轮更新使用的点,初始化时显然只有起点V0被用到,故S内只有V0

用更通俗易懂的话讲,初始化时:

对于visited数组,除了起点对应的值为True,其他均为False

对于dist数组,只要从起点到第i个顶点可以直达,那么disti为起点到该点的距离,否则为∞

对于prev数组,只要从起点到第i个顶点可以直达,那么previ为起点,否则为-1

初始化时dist数组内具体的取值情况:

  • 对于V0,V0到自身距离为0,dist0=0。
  • 对于V1,V0到V1可以直达,V0->V1这条路上Visted值均为True,dist1=length(V0-V1)=10。
  • 对于V2,V0没有办法直接到达V2,必须经过其他点,而任一路径上其他点的visited值均为False,故dist2=∞。
  • 对于V3,同理,V0没有办法直接到达V2,必须经过其他点,而任一路径上其他点的visited值均为False,故dist3=∞。
  • 对于V4,V0到V4可以直达,V0->V4这条路上除终点外Visted值均为True,dist4=length(V0-V4)=5

具体结果如下表所示:

|---------|----|----|----|----|----|
| | V0 | V1 | V2 | V3 | V4 |
| visited | √ | × | × | × | × |
| dist | 0 | 10 | ∞ | ∞ | 5 |
| prev | -1 | 0 | -1 | -1 | 0 |

点集为:S={V0}

例题

例1,如下图所示,使用Dijkstra算法求解V1到各个顶点的最短距离

前边我们说到使用Dijkstra算法求解单源最短路径时,需要使用到三个数组加一个集合。因此,在求解过程中,我们需要不断在其基础上更新,直到图中所有顶点都位于集合S中。在实际做题时,建议大家使用表格的形式来模拟算法执行过程,这样可以方便直观看到每一步的更新情况。

初始化(表0)

|---------|----|----|----|----|----|
| | V0 | V1 | V2 | V3 | V4 |
| visited | √ | × | × | × | × |
| dist | 0 | 10 | ∞ | ∞ | 5 |
| prev | -1 | 1 | -1 | -1 | 1 |

点集为:S={V0}

第一轮(表1)

从表0所对应的dist数组中,发现顶点V4的dist值最小,故本次使用V4来更新路径。将V4加入到路径中,根据dist的更新规则,此时dist数组内各值的调整情况为:

dist0,V0:V0->V0

dist1,V1::V0->V1 or V0->V4->V1 ?

dist2,V2: ∞ or V0->V4->v2

dist3,V3: or V0->V4->v3

dist4,V4:V0->v4

比一比大小,不难得到dist数组最终的取值如表1所示:

|---------|----|----|----|----|----|
| | V0 | V1 | V2 | V3 | V4 |
| visited | √ | × | × | × | √ |
| dist | 0 | 7 | 14 | 7 | 5 |
| prev | -1 | 4 | 4 | 4 | 1 |

点集为:S={V0,V4}

相关推荐
刘马想放假1 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠2 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦9 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠10 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾10 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82110 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q10 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒10 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记10 天前
单项不带头不循环链表
数据结构·链表
小糯米60110 天前
JS 数组
数据结构·算法·排序算法