Dijkstra算法详解(附MATLAB代码)

算法思想

按路径长度递增次序产生算法:

把顶点集合V分成两组:

(1) S: 已求出的顶点的集合 (初始时只含有源点V0)

(2) V-S=T: 尚未确定的顶点集合

将T中顶点按递增的次序加入到S中,保证:

(1)从源点VO到S中其他各顶点的长度都不大于从VO到T中任何顶点的最短路径长度

(2)每个顶点对应一个距离值

S中顶点: 从VO到此顶点的长度

T中顶点: 从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度

依据:可以证明V0到T中顶点Vk的,或是从VO到Vk的直接路径的权值; 或是从V0经S中顶点到Vk的路径权值之和

理解最短路径

既可以是路线最少的路径,也可以是为路径设置的任意含义的数值的最小值(eg. 耗时最少、消费金额最少)

我们称路径关联的含义数值为图的权重(weight)

算法核心在于找到从起点到终点间的每个节点的最少开销,最后再计算出起点到终点的路径.这是基于广度优先的经典算法之一.

在解决问题的途中,需要存储以下三种数据:

(1)原图

(2)每个节点的最少开销

(3)导致节点最少开销的父节点(用以帮助回溯出最短路径)

上图为一有权有向图,每条边上的权重即为该路径的开销,此时显示从起点到B的最少开销是20,是通过A到达B的,则记录B的父节点是A。

遍历:

1)起点状态初始化

2)下一步去哪儿。选择开销最短的节点作为下一个遍历其邻接边的节点

3)对当前节点的处理。计算当前节点到其它节点的开销,如果出现更小的开销就更新2个表:开销散列表、父节点散列表

遍历结束:

4)根据开销表和父节点表,获取路径和最短开销

算法分解

<1> 当前位置:A。最初,从起点开始遍历,开销表和父节点表处于初始状态。此时从起点可以到达的节点只有B、C,遍历A后,因开销表中C的开销最少,所以,下一步,前往C

 <2> 当前位置:C。此时,计算从C可以到达的邻接点的开销,如果有更少的开销,就更新开销表和父节点表。此时,从C到B只需要8,小于原先的20,那么更新表。遍历完C节点后,开销表中,除开已遍历的C节点,开销最短的节点是B,所以,下一步,前往B。 

<3> 当前位置:B。与上一轮更新方法相同,更新表。因D节点即终点,遍历结束。

<4> 计算最短路径和最少开销。如开销表中记录,到终点D的最短开销是10。从父节点表中获取最短路径,终点D的父节点是B,B的父节点是C,C的父节点是起点A,所以,得到最短开销的路径是:A->C->B->D。

 注:该算法适用于无向图和有向图,但不适用于带负权重的图

附:matlab代码

function [d, p] = dijkstra(adj, s, t)
% 使用dijkstra求最短路径
% adj       输入  矩阵          邻接矩阵
% s         输入  整数          起点
% t         输入  整数 或 []    终点
% d         输出  向量          路径长度,若t==[],则返回从起点到所有节点的路径长度
% p         输出  向量 或 元胞   路径,若t==[],则返回从起点到所有节点的路径(cell)
nodes_num = size(adj, 1);
dist = inf(nodes_num, 1);
previous = inf(nodes_num, 1);
Q = [1:nodes_num]';
 
% 求邻居
neighbors = cell(nodes_num, 1);
for i = 1:nodes_num; 
    neighbors{i} = find(adj(i, :) > 0); 
end
 
dist(s) = 0;
while ~isempty(Q)
    % 取出距离最小点
    [~, min_ind] = min(dist(Q));
    min_node = Q(min_ind);
    Q = setdiff(Q, min_node);
 
    % 若是终点,则结束程序
    if min_node == t
        d = dist(min_node);
        p = dijkstra_generate_path(previous, t);
        return;
    end
 
    % 更新邻居的距离
    for i = 1:length(neighbors{min_node})
        neighbor = neighbors{min_node}(i);
        alt = dist(min_node) + adj(min_node, neighbor);
        if alt < dist(neighbor)
            dist(neighbor) = alt;
            previous(neighbor) = min_node;
        end
    end 
end
d = dist;
p = cell(nodes_num, 1);
for i = 1:nodes_num; 
    p{i} = dijkstra_generate_path(previous, i); 
end
end

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行走的参考文献

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值