思路
1.设两个集合为S(V)、D(v),S(V)表示已经最小不能再小集合,而集合 D(v)中存储的是初始顶点v0到顶点v的最短距离(包括本身)
2.对于v0所有能到达的点,记 D(v)= W(v0,v),W(v0, v)表示 v0 到 v 的距离,不能到达的顶点记为 INF
3.选取 D(v)中最小的结点 u 并加入已经最小不能再小集合S(v),然后对 u 的所有邻接点v2,都更新 D(v2)= min(D(v2),D(u) + W(u,v2))
4.重复步骤3,直到S(v)包含了所有顶点
伪代码
// 设出发点为start
dijkstra(start) // 初始化最短路径估计数组d、集合S for i=[0,n) d[i] = map[0][i]
visit[i] = false for i=[1,n) // 寻找最短路径(s,u),同时把u加入S集合 min_d = INF for j=[0,n) if !visit[j] && d[j]<min_d min_d = d[j]//记录最小值和最小值的下标 u = j visit[u] = true // 松弛边(u,v) for v = [0,n) if !visit[v] && map[u][v] != INF d[v] = min(d[v], d[u] + map[u][v])
优化
dijkstra算法可以进一步优化。数据结构采用优先队列(优化的堆),每次更新时将顶点序号和对应的最小距离存入优先队列,这样做的好处是每一次从堆中取出最小值的顶点就是我们需要放入已经最小不能再小集合S(v)的点 ,而堆的入堆出堆操作是 O(lgn) ,运行时间会有很大提高。
伪代码
Dijkstra(G, W, s) //G表示图,W表示权值函数,s表示源顶点 d[s] ←0 //源点到源点最短路为0 for each v ∈ V - {s} //3-8行均为初始化操作 do d[v]←∞ parent[v]←NIL S←∅ Q←V //此处Q为优先队列,存储未进入S的各顶点以及从源点到这些顶点的估算距离,采用最小堆实现,越小越优先 while Q≠∅ do u←Extract-Min(Q) //提取估算距离最小的顶点,在优先队列中位于顶部,出队列,放入集合S中 S←S∪{u} for each v ∈ Adj(u) //松弛操作,对与u相邻的每个顶点v,进行维持三角不等式成立的松弛操作。 do if d[v] > d[u] + w(u, v) then d[v] = d[u] + w(u, v) //这一步隐含了更新优先队列中的值,DECREASE。 parent[v]←u //置v的前驱结点为u,构造路径
如果我们用 parent[v] 记录 v 的父结点,还可以得到一颗最短路径树,利于获取该路径每条边的信息,这种想法在做这次课设《全国交通咨询系统》中有所涉及,可以参考我的另一篇博客:http://www.cnblogs.com/Bw98blogs/p/8203520.html
过图如下(着色表示将顶点加入S(v))