Dijkstra算法
介绍
Dijkstra算法,是用于求解图(这里介绍有向图)的最短路径算法。采用贪婪原则,逐步求解起点到图其他点的最短路径。
算法描述
从起点出发,寻找距离最近的点,找到距离最近的点,再尝试将最近的点作为中间点,来计算到其他点的距离,看是否相对之前有所减少,减少就记录下这个距离,再次寻找剩余点中距离最近的点,知道所有点都被选中。
这么描述可能很抽象,结合例子来看:
图在数据结构中,有多种表现方式,这里采用邻接矩阵记录
到自身距离为0,没有直接相连记为无穷
需要三个数组:
dist[j]:表示起点到j点的最短距离
path[j]=i:表示到达j点前经过的最后一个点为i
set[i](布尔):表示是否求得起点到i的距离
(1)初始化
假设0为起点,图转化的临界矩阵为M,需要做以下初始化
- set[0]=true,标记0已经求得,set[i]=false(i!=0),标记其他点未读
- dist[i]=M0i,将0到其他点的距离作为最短路径
- path[i]=-1,-1表示没有起点,path[i]=j表示0->…->j->i,因此,如果M0j不是无穷,则表示最短路径经0点,令path[j]=0,否则path[j]=-1
(2)迭代求解
每一次计算都会得到起点到一个点的最短距离,所以只需要n-1(n为顶点个数)就可以求出到所有点的最短路径,一下过程需要重复执行n-1次:
- 根据dist[]数据找到值最小的点j,dist[j]就是起点到j的最短距离
- set[j]=true,标记起点到j的最短距离已找到
- path[j]=preNode,记录起点到达j的最短路径上,经过preNode才到达j,即preNode是起点到达j的最短路径上的倒数第二个节点
- 更新dist[],尝试将j作为中间点,来减少起点到达剩余点的距离,如果dist[k]>dist[j]+Mjk(其中set[k]==false),则令dist[k]=dist[j]+Mjk,且令path[k]=j,记录下最短路径上的倒数第二点
(3)结果
按照上述步骤,得到计算结果:
path: [ -1, 4, 1, 4, 0 ]
dist: [ 0, 8, 9, 7, 5 ]
解析:
目的节点 | 最短路径 | 距离 |
---|---|---|
0 | 0->0 | 0 |
1 | 0->4->1 | 8 |
2 | 0->4->3->1->2 | 9 |
3 | 0->4->3 | 7 |
4 | 0->4 | 5 |
TypeScript实现
模块化./modules/Dijkstra.ts
const Dijkstra = (startNode:number,map:number[][]):any=>{
let dist:number[]=[]
let path:number[]=[]
let set:boolean[]=[]
// 初始化
for(let i=0;i<map[0].length;i++){
if(startNode!==i){
dist[i]=map[startNode][i]
set[i]=false
if(map[startNode][i]!=Number.MAX_VALUE){
path[i]=startNode
}
}else{
dist[i]=0
set[i]=true
path[i]=-1
}
}
let preNode:number=startNode
for(let i=1;i<map.length;i++){
const {min,minIndex}=getMinAndIndex(dist,set)
if(minIndex==-1)return false;
set[minIndex]=true
// 更新dist
for(let j=0;j<map.length;j++){
if(set[j]!==true&&dist[j]>dist[minIndex]+map[minIndex][j]){
dist[j]=dist[minIndex]+map[minIndex][j]
// 选出到达目的距离最短的点
path[j]=minIndex
}
}
//console.log(min,minIndex);
}
return {
path,dist
}
}
const getMinAndIndex=(arr:number[],set:boolean[]):any=>{
let min:number=Number.MAX_VALUE
let minIndex:number=-1
for(let i=1;i<arr.length;i++){
if(set[i]===false && min>arr[i]){
min=arr[i]
minIndex=i
}
}
return {
min,minIndex
}
}
export {getMinAndIndex,Dijkstra}
测试
import {getMinAndIndex,Dijkstra} from './modules/Dijkstra'
let inf:number=Number.MAX_VALUE
let arr:number[][]=
[
[0,10,inf,inf,5],
[inf,0,1,inf,2],
[inf,inf,0,4,inf],
[inf,inf,6,0,inf],
[inf,3,9,2,inf]
]
let res = Dijkstra(0,arr)
console.log(res)
结果:
总结
Dijkstra算法,用于解决图的最短路径问题,一起点为中心,逐步向四周扩散,通过不断的更新路径,来尝试获得最短路径,采用贪婪的思想,获得触发点到其余点的最短路径及最短距离,Dijkstra算法具有广泛的应用。