原理
迪杰斯特拉算法是一个单源点最短路径算法,即该算法会求得从指定一个顶点(源点)到其余所有顶点的最短路径。
这里用到一个想法是一个问题的最优解一定包含子问题的最优解,以找最短路为例子,如果从起点出发,选择抵达下个点用的代价最小的点,然后按照这个原则依次选择下一个点,那么抵达终点前所选择的路径一定是最短的
这里实现的没有去检测是否存在负权路径,也没有检测图本身是否为强连通,总之就是这个实现的只能对存在最短路径且无负权路径的图求单源最短路径
与最小生成树Prim算法的区别
最大的区别
最小生成树所构建的是一个树,也就意味着会有分叉点,
但是单源最短路径最后生成的是一条路,没有分支点。
在执行的过程中的区别(可以看下我之前写的Prim算法的对比)
最小生成树会遍历检测已经选择完成的所有点的其他安全边
去选择最小的下个边从而获得下个点
单源最短路径只会遍历被选择的点的安全便选择下个边获得下个点
伪代码
while(点还没选完)
for(选择的点的所有边){
if(当前选择的点的距离+当前选择的点抵达下个点的距离 < 下个点的距离(这个距离就不一定是当前选择的点抵达下个点的距离))
下个点的距离 = 当前选择的点的距离+当前选择的点抵达下个点的距离
}
选择的点 = 遍历过得所有边中最短的距离的那条边的终点
选择下个点的整体过程
PS:这里的过程是一个公众号中所画出的,名字叫景禹
代码实现
数据
var NumNodes = 9;
var NumEdges = 16;
var start = [0,0,1,1,1,2,2,3,4,3,4,4,5,6,6,7];
var end = [1,2,2,3,4,4,5,4,5,6,6,7,7,7,8,8];
var weight = [1,5,3,7,5,1,7,2,3,3,6,9,5,2,7,4];
代码
function dijkstra(){
//这个算法的整体走的过程和最小生成树的点维护过程很类似,但是这里只对最后加入的点进行维护选择
let Nodelength = new Array(NumNodes);
for (let i = 0; i < NumNodes; i++) {
let temp = new Array(NumNodes);
for (let j = 0; j < NumNodes; j++) {
if (i === j) {
temp[j] = 0;
} else {
temp[j] = 9999;
}
}
Nodelength[i] = temp;
}
for (let i = 0; i < weight.length; i++) {
//start[i],end[i],weight[i]
Nodelength[start[i]][end[i]] = weight[i];
Nodelength[end[i]][start[i]] = weight[i];
}
//这里假设为0为起始点,8为结尾点
//先初始化0点相关的点
let parent = []; //前面的点
let key = []; //到达这个点的距离
let used = {
0: 1
}; //已使用点记录
for (let i = 0; i < NumNodes; i++) {
parent[i] = "null";
key[i] = 9999;
}
key[0] = 0;
let nownode = 0;
for(let k = 0; k < NumNodes; k++){
//遍历当前正在看的点的各个边,去更新距离
let start = 0;
let end = 0;
let weight = 9999;
for(let i = 0; i < NumNodes; i++){
if(Nodelength[nownode][i] != 9999 && nownode != i && used[i] == undefined){
if((Nodelength[nownode][i] + key[nownode]) < key[i]){
//如果经过这个点抵达i点的距离小于原来记录的抵达i的距离并且这里没有成环则更新这个距离
key[i] = Nodelength[nownode][i] + key[nownode];
parent[i] = nownode;
}
//维护边后再看看这个边是不是所需要的边
if (weight > Nodelength[nownode][i]) {
weight = Nodelength[nownode][i];
start = nownode;
end = i;
}
}
}
used[end] = 1;
nownode = end;
}
for (let i = 0; i < parent.length; i++) {
document.write(parent[i] + "->" + i + ":" + key[i] + "</br>");
}
}