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[] 值均爲無窮大

在這裏插入圖片描述
在這裏插入圖片描述

算法實現

在 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);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章