1. 按
Dijkstra算法用于求解一个顶点到另一顶点的最短路径,它采用了非暴力的贪心思想,因此时间复杂度较低,为O(N^2)。
Dijkstra算法是一种贪心算法,每一次都求最短路径,但与常见的贪心算法不同的是,Dijkstra算法是一种步步为营的贪心算法,因此能求解一个顶点到另一个顶点的最短路径。
2. 算法讲解
2.1. 理论讲解
- 约定AimedPathNodes为所要求解的从某一目标点HeadNode(为了便于理解,将此节点约定为HeadNode,即头结点,目标路径上开头的那个节点)到另一目标点TrailNode(为了便于理解,将此节点约定为TrailNode,即尾结点,目标路径上结尾的那个节点)的最短的目标路径。
- 目标路径是由多个点组成的,刚开始时目标路径AimedPathNodes仅包含起始点HeadNode。
- 找出当前目标路径(AimedPathNodes)的最近的邻接点并将其加入到AimedPathNodes中,随后再次找出AimedPathNodes的最近邻接点,并将其加入到AimedPathNodes中,这样一直下去,直到AimedPathNodes包含结尾的那个点(TrailNode)为止。
2.2. 实例讲解
2.2.1. 初始化
给每个点进行编号v1、v2 … v11,这里的v是vertex的缩写,是点的意思,因此v1是点1的意思。
给每条边初始化一个权重,权重用数字表示,如下图中v1与v2两点间的边的权重为2。
此例用于求解v1到v11两点间的最短路径。
约定AimedPathNodes为一个存储目标路径上所有点的变量。
2.2.2. 执行算法
- 刚开始时AimedPathNodes仅包含v1
- 此时AimedPathNodes为v1。
找AimedPathNodes最近的邻接点,即找v1的最近的邻接点。
与v1相邻的点为v2、v3、v4,因此v1的邻接点为v2、v3、v4。
其中v1与v2的边权重位2,v1与v3的边权重位8,v1与v4的边权重位1。
易得:v1的最近邻接点为v4
将v4加入到AimedPathNodes。
- 此时AimedPathNodes为v1, v4。
找AimedPathNodes的最近邻接点,即先找出v1的不包含AimedPathNodes上的点的最短邻接点v2,再找出v4的不包含AimedPathNodes上的点的最近邻接点v3。
由于v1到v2的距离为2,v4到v3的距离为7,因此v2为到此时AimedPathNodes的最近点,将v2加入到AimedPathNodes。
- 此时AimedPathNodes为v1, v4, v2。
易得AimedPathNodes的最近邻接点为v5,将v5加入到AimedPathNodes中
- 此时AimedPathNodes为v1, v4, v2, v5。
易得AimedPathNodes的最近邻接点为v8
- 此时AimedPathNodes为v1, v4, v2, v5, v8。
AimedPathNodes的最近邻接点为v6
- 此时AimedPathNodes为v1, v4, v2, v5, v8, v6。
AimedPathNodes的最近邻接点为v3
- 此时AimedPathNodes为v1, v4, v2, v5, v8, v6, v3。
AimedPathNodes的最近邻接点为v7
- 此时AimedPathNodes为v1, v4, v2, v5, v8, v6, v3, v7。
AimedPathNodes的最近邻接点为v10
- 此时AimedPathNodes为v1, v4, v2, v5, v8, v6, v3, v7, v10。
AimedPathNodes的最近邻接点为v9
- 此时AimedPathNodes为v1, v4, v2, v5, v8, v6, v3, v7, v10, v9。
AimedPathNodes的最近邻接点为v11
- 停止找最近的邻接点。实际求解最短路径时,除了上面的之外,还要再声明一个变量用于存储最短路径,并且每一步还有一个对该变量进行退栈和入栈的操作。
3. matlab实现
dijkstra.m
function [min,path]=dijkstra(w,start,terminal)
n=size(w,1); label(start)=0; f(start)=start;
for i=1:n
if i~=start
label(i)=inf;
end, end
s(1)=start; u=start;
while length(s)<n
for i=1:n
ins=0;
for j=1:length(s)
if i==s(j)
ins=1;
end,
end
if ins==0
v=i;
if label(v)>(label(u)+w(u,v))
label(v)=(label(u)+w(u,v));
f(v)=u;
end,
end,
end
v1=0;
k=inf;
for i=1:n
ins=0;
for j=1:length(s)
if i==s(j)
ins=1;
end,
end
if ins==0
v=i;
if k>label(v)
k=label(v); v1=v;
end,
end,
end
s(length(s)+1)=v1;
u=v1;
end
min=label(terminal); path(1)=terminal;
i=1;
while path(i)~=start
path(i+1)=f(path(i));
i=i+1 ;
end
path(i)=start;
L=length(path);
path=path(L:-1:1);
4. 测试
4.1. 测试一
- 代码
weight=[0 2 8 1 Inf Inf Inf Inf Inf Inf Inf; 2 0 6 Inf 1 Inf Inf Inf Inf Inf Inf; 8 6 0 7 5 1 2 Inf Inf Inf Inf; 1 Inf 7 0 Inf Inf 9 Inf Inf Inf Inf; Inf 1 5 Inf 0 3 Inf 2 9 Inf Inf; Inf Inf 1 Inf 3 0 4 Inf 6 Inf Inf; Inf Inf 2 9 Inf 4 0 Inf 3 1 Inf; Inf Inf Inf Inf 2 Inf Inf 0 7 Inf 9; Inf Inf Inf Inf 9 6 3 7 0 1 2; Inf Inf Inf Inf Inf Inf 1 Inf 1 0 4; Inf Inf Inf Inf Inf Inf Inf 9 2 4 0;] [dis, path]=dijkstra(weight,1, 11)
- 图
- 结果
dis = 13
path = 1 2 5 6 3 7 10 9 11
4.2. 测试二
- 代码
weight=[0 8 Inf Inf Inf Inf 7 8 Inf Inf Inf; Inf 0 3 Inf Inf Inf Inf Inf Inf Inf Inf; Inf Inf 0 5 6 Inf 5 Inf Inf Inf Inf; Inf Inf Inf 0 1 Inf Inf Inf Inf Inf 12; Inf Inf 6 Inf 0 2 Inf Inf Inf Inf 10; Inf Inf Inf Inf 2 0 9 Inf 3 Inf Inf; Inf Inf Inf Inf Inf 9 0 Inf Inf Inf Inf; 8 Inf Inf Inf Inf Inf Inf 0 9 Inf Inf; Inf Inf Inf Inf 7 Inf Inf 9 0 2 Inf; Inf Inf Inf Inf Inf Inf Inf Inf 2 0 2; Inf Inf Inf Inf 10 Inf Inf Inf Inf Inf 0;]; [dis, path]=dijkstra(weight,1, 11)
- 图
- 结果
dis = 21
path = 1 8 9 10 11