4.4 Dijkstra算法
category
type
status
slug
date
summary
tags
password
icon
你不能改变过去,但你可以改变未来。
—《狮子王》
🏰代码及环境配置:请参考 环境配置和代码运行!
DFS算法无法找到最优解,BFS算法仅仅适用于无权图或者权重相同的图,而Dijkstra算法适用于带有非负权重的有向图和无向图。其由荷兰计算机科学家Edsger W. Dijkstra在1956年提出,是一种用于在图中找到单源最短路径的算法,解决了从图中一个顶点到其他所有顶点的最短路径问题,此外,如果知道了源节点到目标节点的最短路径,算法也可以提前终止。
4.4.1 数据结构-优先队列
优先队列(priority queue)是一种抽象的数据类型,其与普通队列(queue)相似但也有所不同,其特性如下:
- 优先队列中的每个元素都有相对应的优先级。
- 在进行移除元素操作时,高优先级的元素将优先被移除。
- 如果两个元素的优先级相同,则按照先进先出(FIFO)的原则进行排序。
其特性表明优先级队列只支持可比较的元素,这意味着元素要么按升序排列,要么按降序排列。
升序优先队列: 小值拥有更高的优先级
降序优先队列: 大值拥有更高的优先级
4.4.2 基本思想
Dijkstra算法的基本思想是从一个源节点开始,逐步向外探索,直至找到从源节点到所有其他节点(或者目标节点)的最短路径。相比较于BFS,其维护了每个节点到源节点的最小累计cost:,每次从队列中取的是cost最小的节点,而非先进入队列的节点。
其算法步骤如下:
- 初始化:
- 创建一个数组
g[]
,其中g[i]
表示从源节点start
到节点i
的最小cost,初始时,源节点的cost为0。 - 创建一个布尔数组
visited[]
来跟踪每个节点是否已被访问过,初始时,所有顶点都未访问 - 创建一个优先队列
open_list
,用于根据cost选择下一个要处理的节点。优先队列中的每个元素是一个包含顶点和cost的配对,初始时将源节点start
和其cost
(0)加入优先队列。
- 循环处理优先队列中的节点:
- 从优先队列中取出cost最小的节点
v
,并将节点v
标记为已访问,若节点v
就是目标节点,则提前返回。 - 遍历节点
v
中所有未被访问过的邻接节点,对于每一个邻接节点next
: - 计算邻接节点
next
的cost。 - 若邻接节点
next
不在优先队列中,则将邻接节点next
和其对应的cost加入优先队列,并在数组g[]
中设置邻接节点next
的cost,最后将临接节点next
的父节点设为v
。 - 若邻接节点
next
在优先队列中,则在数组g[]
和优先队列open_list
中更新节点next
的相关信息,最后将临接节点next
的父节点设为v
。 - 继续处理优先队列中的顶点,直到队列为空或所有顶点都被访问。
- 从目标节点
goal
开始,通过父节点向回追溯,直到起始节点,最终得到一条路径。
其伪代码如下:
4.4.3 Dijkstra算法的图解
以从下面的无向图中寻找出节点
0
到其他所有节点的最短路径为例,其中两个节点之间的权重表示他们之间的距离(或者cost),并初始话两个表:visited nodes info和unvisited nodes info。所有节点的初始cost如下:
- 源节点到自身的cost为0。
- 源节点到其它节点的cost还没有确定,暂时先标记为无穷大。
- 从源节点
0
开始,将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新源节点0
的邻近节点(节点1
和节点2
)的信息。 - 节点
1
:节点1
最短路径为0 —> 1
,cost为2,父节点为0
。 - 节点
2
:节点2
最短路径为0 —> 2
,cost为6,父节点为0
。
- 查看未访问列表,节点
1
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新节点1
的邻近节点(节点3
)的信息。 - 节点
3
:节点3
的最短路径为0 —> 1 —> 3
,cost为7,父节点为1
。
- 查看未访问列表,节点
2
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新节点2
的邻近节点(节点3
)的信息。 - 节点
3
:此时,节点3
有两条可选路径:0 —> 1 —> 3
和0 —> 2 —> 3
,前者的cost是7,后者的cost是14,因此选择前者,即节点3
的最短路径为0 —> 1 —> 3
,cost为7,父节点为1
。
- 查看未访问列表,节点
3
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新节点3
的邻近节点(节点4
和节点5
)的信息。 - 节点
4
:节点4
的最短路径为0 —> 1 —> 3 —> 4
,cost为17,父节点为3
。 - 节点
5
:节点5
的最短路径为0 —> 1 —> 3 —> 5
,cost为22,父节点为3
。
- 查看未访问列表,节点
4
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新节点4
的邻近节点(节点5
和节点6
)的信息。 - 节点
5
:此时节点5
有两条可选路径:0 —> 1 —> 3 —> 5
和0 —> 1 —> 3 —> 4 —> 5
,前者的cost是22,后者的cost是23,因此选择前者,即节点5
的最短路径为0 —> 1 —> 3 —> 5
,父节点为3
。 - 节点
6
:节点6
的最短路径为0 —> 1 —> 3 —> 4 —> 6
,cost为19,父节点为4
。
- 查看未访问列表,节点
6
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新节点6
的邻近节点(节点5
)的信息。 - 节点
5
:此时节点5共有3条可选路径(如下),因此最短路径为0 —> 1 —> 3 —> 5
,cost为22,父节点为3
。 0 —> 1 —> 3 —> 5
,cost为22。0 —> 1 —> 3 —> 4 —> 5
,cost为23。0 —> 1 —> 3 —> 4 —> 6 —> 5
,cost为25。
- 查看未访问列表,节点
5
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。此时未访问列表中没有节点,因此搜索结束。此时,我们可以给定目标节点,并通过回溯父节点的方式找到从源节点到目标节点的最短路径。例如我们另节点6
是目标节点,可以得到从源节点到目标节点的最短路径为:0 —> 1 —> 3 —> 4 —> 6
4.4.4 Dijkstra算法特点
- 优点:
(1)总能找到从单个源点到图中所有其他顶点的最短路径,前提是所有的边权重都是非负的。
(2)原理简单,应用广泛,且满足最优性原则。
- 缺点:
(1)搜索时没有引入目标节点的信息,导致搜索效率较低。
(2)不适用于包含负权重的图。
4.4.5 参考
上一篇
动手学控制理论
下一篇
端到端-理论与实战视频课程
Loading...