Dijkstra算法

Dijkstra算法

Dijkstra算法能够解决边权重非负的加权有向图的单起点最短路径问题

在之前,我们讨论过寻找加权无向图中的最小生成树的Prim算法:构造最小生成树的每一步都向这棵树中添加一条新的边。

Dijkstra算法采用了类似的方法来计算最短路径树。首先将 distTo[] 最小的非树顶点放松并加入树中,如此直到所有的顶点都在树中或者所有非树顶点的 distTo[] 值均为无穷大。


数据结构

要实现 Dijkstra算法,除了 distTo[] 和 edgeTo[] 数组之外还需要一条 索引优先队列 pq,以保存需要被放松的顶点并确认下一个被放松的顶点。

IndexMinPQ 可以将索引和键(优先级)关联起来,并且可以删除并返回优先级最低的索引。在这里,只要将顶点v 和 distTo[v] 关联起来就可以得到 Dijkstra 算法的实现。


算法步骤:
1)distTo[s] = 0, distTo[v] = INFINITY (v≠s)
2)将 distTo[] 中离顶点 s 最近的非树顶点放松, 并加入到树中
3)重复2,直到所有顶点都在树中或者所有的非树顶点的 distTo[] 值均为无穷大

Dijkstra算法_第1张图片
Dijkstra算法_第2张图片

算法实现

在 relax() 方法中添加了一行语句来处理以下两种情况:
1、边的 to() 得到的顶点不在优先队列中,此时需要使用 insert() 方法将它加入到优先队列中
2、它已经在优先队列中,且优先级需要被降低,此时需要使用 change() 方法实现

思考 Dijkstra算法的另一种方式就是将它和 Prim算法相比较。两种算法都会用添加边的方式构造一棵树:Prim算法每次添加的都是 离树最近 的非树顶点;Dijkstra算法每次添加的都是 离起点最近 的非树顶点。

/* 
 * 单起点最短路径的 Dijkstra算法
 */
 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<Double>(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) // standard client query methods
     public boolean hasPathTo(int v) // for SPT implementatations
     public Iterable<Edge> pathTo(int v) // (See page 649.)
 }
 

任意顶点对的最短路径

给定两点的最短路径:给定一幅加权有向图和一个起点 s 、一个终点 t,是否存在一条从 s 到 t 的路径?如果有,找出最短的那条路径。

算法构造了 DijkstraSP对象 的数组,每个元素都将相应的顶点作为起点。在用例进行查询时,代码会访问起点所对应的单点最短路径对象,并将目的顶点作为参数进行查询。

/*
 * 任意顶点对之间的最短路径
 */
public class DijkstraAllPairsSP {
    private DijkstraSP[] all;

    DijkstraAllPairsSP(EdgeWeightedDigraph G)
    {
        all = new DijkstraSP[G.V()];
        for (int v = 0; v < G.V(); v++)
            all[v] = new DijkstraSP(G, v);
    }

    Iterable<Edge> path(int s, int t) {
        return all[s].pathTo(t);
    }

    double dist(int s, int t) {
        return all[s].distTo(t);
    }
}


你可能感兴趣的:(图)