Dijkstra算法是由Dijkstra发明的,他是一名伟大的计算机科学家,发明过许多算法,
基本思想
Dijkstra算法的基本思想是,开始的时候先将最短路径树设为空,每次将顶点加入最短路径树的时候对该顶点延伸出的所有边进行“放松 ”操作。然后先将原点加入到最短路径树中,依次将距离原点最近的点加入到最短路径树中。
代码
public class DijkstraSP extends SP {
private IndexMinPQ<Double> pq;
public DijkstraSP(EdgeWeightedDigraph G, int s) {
super(G, s);
pq = new IndexMinPQ<Double>(G.V());
// 所有的点到原点的距离都是无穷大
for (int i = 0; i < G.V(); i++) {
distTo[i] = Double.POSITIVE_INFINITY;
}
// 原点到原点的距离是0
distTo[s] = 0;
pq.insert(s, 0.0);
// 依次访问距离最近的点
while (!pq.isEmpty()) {
visit(G, pq.delMin());
}
}
private void visit(EdgeWeightedDigraph G, int v) {
// 放松该顶点延伸出的所有边
for (DirectedEdge e : G.adj(v)) {
this.relax(e);
}
}
@Override
protected void relax(DirectedEdge edge) {
int v = edge.from();
int w = edge.to();
if (distTo[w] > distTo[v] + edge.weight()) {
distTo[w] = distTo[v] + edge.weight();
edgeTo[w] = edge;
if (pq.contains(w)) {
pq.decreaseKey(w, distTo[w]);
} else {
pq.insert(w, distTo[w]);
}
}
}
}
其实Dijkstra算法和Prim饿汉式算法是同一个算法。Prim算法寻找到距离上一个顶点最近的顶点进行展开,而Dijkstra算法寻找距离原点最近的顶点进行展开。
复杂度
一般在实际应用中会使用二叉堆方式实现优先级队列,在这种情况下Dijkstra算法的复杂度为E logV。如果使用其他方式实现优先级队列,那么复杂度会不一样。