算法描述
- 描述1:初始化distTo[s]为0,其余distTo[]为∞,之后逐个将distTo[]中最小非树结点放松,直到所有结点都在树中或所有非树结点distTo[]为∞(s不可达)
- 描述2:初始化后从s开始放松:将与s间隔一条边的顶点加入队列中,按权值小到大对所有间隔一条边结点都进行放松,然后是间隔两条边…结束条件同上
数据结构
- distTo[]:标记s->w的最短距离
- edgeTo[]:标记s->w最短路径的最后一条边
- IndexMinPQ:以”w”为索引,distTo[w]为键的索引优先队列,delMin()保证可以删除并返回路径最短的顶点
算法证明
证明:若v是起点可达的,v被放松时一定满足distTo[w]<=distTo[v]+e.weight(),放松v前的结点时,delMin()保证了distTo[v]一定是最小的,不会再改变,则distTo[w]只会变小,如此对每个顶点distTo[]都是最小的,且满足distTo[w]<=distTo[v]+e.weight(),根据最短路径最优性条件(书P420),则得到的distTo[]都是最短路径长度
实现
import edu.princeton.cs.algs4.IndexMinPQ;import edu.princeton.cs.algs4.Stack;public class DijkstraSP {private DirectedEdge[] edgeTo;private double[] distTo;private IndexMinPQ<Double> pq;public DijkstraSP(EdgeWeightedDigraph G, int s){edgeTo = new DirectedEdge[G.V()];distTo = new double[G.V()];pq = new IndexMinPQ<>(G.V());for (int v = 0; v < G.V(); v++)distTo[v] = Double.POSITIVE_INFINITY;distTo[s] = 0.0;pq.insert(s, 0.0);while (!pq.isEmpty()){relax(G, pq.delMin());}}private void relax(EdgeWeightedDigraph G, int v){for (DirectedEdge e: G.adj(v)){int w = e.to();if (distTo[w] > distTo[v]+e.weight()){distTo[w] = distTo[v]+e.weight();edgeTo[w] = e;if (pq.contains(w)) pq.change(w, distTo[w]);else pq.insert(w, distTo[w]);}}}public double distTo(int v){ return distTo[v];}//s->v的距离public boolean hasPathTo(int v){ return distTo[v] < Double.POSITIVE_INFINITY;}public Iterable<DirectedEdge> pathTo(int v){Stack<DirectedEdge> stack = new Stack<>();for(DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()])stack.push(e);return stack;//后根入栈}}
示例
算法分析
- G(V,E)中使用Dijkstra算法构建SPT所需空间和V成正比,时间和ElogE成正比(最坏)
证明:与使用索引优先队列的Prim一致
任意两顶点间最短路径
- 与算法4.6中建立传递闭包获得顶点对可达性类似,通过建立DijkstraSP[]判读顶点s,t直接知否有最短路径,已经最短路径大小
public class DijkstraAllPairsSP {private DijkstraSP[] all;public DijkstraAllPairsSP(EdgeWeightedDigraph G){all = new DijkstraSP[G.V()];for (int v = 0; v < G.V(); v++){all[v] = new DijkstraSP(G, v);}}//返回s->t最短路径Iterable<DirectedEdge> path(int s, int t){ return all[s].pathTo(t);}//返回s->t最短路径大小double dist(int s, int t){ return all[s].distTo(t); }}
