『算法設計_偽代碼』貪心算法_最短路徑Dijkstra算法


Dijkstra算法實際上是一個貪婪算法(Greedy algorithm)。因為該算法總是試圖優先訪問每一步循環中距離起始點最近的下一個結點。Dijkstra算法的過程如下圖所示。

Dijkstra Animation

初始化

  1. 給定圖中的一個結點s作為起始點。
  2. 給定一個數組dist[]存儲圖中所有結點到s的距離。將dist[s]初始化為0。對於圖中的其他結點v,初始化dist[v]為無窮大。初始化為無窮大的意義在於我們假設其余所有結點在當前情況下尚未與s聯通。隨着算法的執行,dist[v]會保存圖中從sv的最短路徑的距離。
  3. 給定一個minimum Heap,記為Q。堆頂為當前情況下距離s最近的結點及相應的距離。將(s, 0)放入堆中。
  4. 給定一個Set,記為S,保存所有已經訪問過的結點。Set初始為空。基於Dijkstra算法的性質,我們總是以最短的路徑遍歷每一個結點,因此對於任一結點,一旦我們已經訪問過,就代表着我們已經得到了從s到達這一結點的最短路徑。

計算最短路徑

  1. Q不為空的情況下,取出堆頂的元素(v, [dist[v]) —— 也就是當前距離s最近的結點v,及其距離dist[v]
  2. 如果vS中,則代表我們已經訪問過v的最短路徑。那么跳過當前v,重復步驟1。
  3. 否則,將v放在S中。
  4. 對於每一個與v相鄰的結點t
    • 如果dist[v] + weight(v, t) < dist[t],則更新dist[t] = dist[v] + weight(v, t)。同時將(t, dist[t])放進Q中。
    • 否則,不做任何處理。

當算法結束后,dist[]中保存圖中每一個除s之外的結點到s的最短路徑的權重值(或長度)。如果從sv不存在聯通的路徑,則dist[v] = ∞

證明算法正確性

假設對於每個已經訪問過的結點vdist[v]存儲從起始點sv的最短路徑。

當算法初始化時,dist[]中只包含dist[s] = 0,其正確性顯而易見。

對於其余n-1個結點,假設u已經被訪問且v尚未被訪問,同時uv之間存在一條邊u -> v,其權重為weight(u,v),那么一定有dist[v] = dist[u] + weight(u, v)。否則的話,假設存在另一條更短的路徑dist[t]滿足dist[t] + weight(t, v),則根據上述算法,t一定先於u被訪問,則與我們當前的假設產生了矛盾。該論斷對於余下的所有結點都成立。

因此Dijkstra算法一定能給出從出發點到其余所有結點(在可以到達的情況下)的最短路徑。

復雜度分析

設圖中總計有E條邊,N個結點。

時間復雜度:O(ElogE)。因為所使用的最小堆最大可達O(E)大小,同時我們從其中將每個元素取出來一次。

空間復雜度:O(N+E)。其中O(N)為存儲dist所用空間。O(E)為存儲圖的鄰接鏈表及最小堆所用空間。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM