Dijkstra算法是解决单源最短路径问题的一种经典算法,用于求解从一个固定源点到图中所有其他节点的最短路径。
算法步骤如下:
1.创建一个空的距离数组 distance,用于记录源点到各个节点的当前估计最短路径值。
2.将源点的距离值初始化为0,将所有其他节点的距离值初始化为无穷大。
3.创建一个空的已访问集合 ,用于记录已经找到最短路径的节点。
4.重复以下步骤,直到所有节点都被访问:
a. 从未访问过的节点中选择一个距离值最小的节点,将其标记为已访问。
b. 更新与该节点相邻的未访问节点的距离值,如果通过该节点到达这些节点的路径距离比当前记录的最短路径值要短,则更新最短路径值。
5.最终,所有节点的最短路径值记录在一个 数组中。
Dijkstra算法的伪代码表示如下:
输入: 图G, 源点s
输出: 源点s到图G中所有其他节点的最短路径初始化:
1. 创建距离数组 ,将源点s的距离值设为0,将其他节点的距离值设为无穷大。
2. 创建空的已访问集合 。while 未访问的节点非空:
3. 选取距离值最小的未访问节点 u,将其标记为已访问。
4. 遍历节点 u 的所有邻居节点 v:
- 如果通过节点 u 到达节点 v 的路径距离更短,则更新最短路径值 distance[v]。
5. 标记节点 u 已访问。返回距离数组
Dijkstra算法保证在无负权边的情况下找到源点到图中所有其他节点的最短路径。如果某些节点无法通过路径到达,则其最短路径值将保持为无穷大即inf
本文修改了该文章一些地方,并详细标注和补充
如有下方距离矩阵:
Inf 50 Inf 40 25 10;
50 Inf 15 20 Inf 25;
Inf 15 Inf 10 20 Inf;
40 20 10 Inf 10 25;
25 Inf 20 10 Inf 55;
10 25 Inf 25 55 Inf
程序:
clc,clear all
a=[ Inf 50 Inf 40 25 10;
50 Inf 15 20 Inf 25;
Inf 15 Inf 10 20 Inf;
40 20 10 Inf 10 25;
25 Inf 20 10 Inf 55;
10 25 Inf 25 55 Inf];
pb(1:length(a))=0;
pb(1)=1; %当一个点已经求出到原点的最短距离时,其下标i对应的pb(i)赋1,即0-1变量
index1=1; %标号顶点顺序
index2=ones(1,length(a)); %~索引
d(1:length(a))=inf;d(1)=0; %存放由始点到第i点最短通路的值
temp=1; %表示起始节点为1
while sum(pb)<length(a) %看是否所有的点都标记为P标号
tb=find(pb==0); %找到标号为0的所有点,即找到还没有存入的点
d(tb)=min(d(tb),d(temp)+a(temp,tb));
%d(temp) 表示起点到当前访问节点 temp 的最短路径值。a(temp, tb) 表示当前访问节点 temp 到点集 tb 所有点的距离。 d(tb) 是存放从起点到每个节点的最短路径值的向量。通过计算 d(temp) + a(temp, tb),得到起点经过当前访问节点 temp 到达点集 tb 的距离。然后将这个值与 d(tb) 中原先存储的最短路径进行比较,选取较小的值用于更新最短路径
tmpb=find(d(tb)==min(d(tb))); %求d[tb]序列最小值的下标
temp=tb(tmpb(1));%可能有多条路径同时到达最小值,却其中一个,temp也从原点变为下一个点
pb(temp)=1;%找到最小路径的表对应的pb(i)=1
index1=[index1,temp]; %存放存入集合的顺序
temp2=find(d(index1)==d(temp)-a(temp,index1));
index2(temp)=index1(temp2(1)); %记录标号索引
end
d, index1, index2
输出结果:
d =0 35 45 35 25 10
index1 =1 6 5 2 4 3
index2 =1 6 5 6 1 1
罚函数法:
function [mydistance,mypath]=mydijkstra(a,sb,db);
% 输入:a—邻接矩阵,a(i,j)是指i到j之间的距离,可以是有向的
% sb—起点的标号, db—终点的标号
% 输出:mydistance—最短路的距离, mypath—最短路的路径
n=size(a,1); visited(1:n) = 0;
distance(1:n) = inf; distance(sb) = 0; %起点到各顶点距离的初始化
visited(sb)=1; u=sb; %u为最新的P标号顶点
parent(1:n) = 0; %前驱顶点的初始化
for i = 1: n-1
id=find(visited==0); %查找未标号的顶点
for v = id
if a(u, v) + distance(u) < distance(v)
distance(v) = distance(u) + a(u, v); %修改标号值
parent(v) = u;
end
end
temp=distance;
temp(visited==1)=inf; %已标号点的距离换成无穷
[t, u] = min(temp); %找标号值最小的顶点
visited(u) = 1; %标记已经标号的顶点
end
mypath = [];
if parent(db) ~= 0 %如果存在路!
t = db; mypath = [db];
while t ~= sb
p = parent(t);
mypath = [p mypath];
t = p;
end
end
mydistance = distance(db);
调用方法:
clc,clear all; a = [ Inf 50 Inf 40 25 10 50 Inf 15 20 Inf 25 Inf 15 Inf 10 20 Inf 40 20 10 Inf 10 25 25 Inf 20 10 Inf 55 10 25 Inf 25 55 Inf];%可换成自己的距离矩阵 sb = 1; % 起点是节点1 db = 3; % 终点是节点3 [mydistance, mypath] = mydijkstra(a, sb, db); disp(['最短路径长度: ' num2str(mydistance)]); disp(['最短路径: ' num2str(mypath)]);