1. 程式人生 > 其它 >Dijkstra計算加權無向圖的最短路徑

Dijkstra計算加權無向圖的最短路徑

【理論知識的,可以參考】

漫畫:圖的最短路徑問題

最短路徑演算法

該演算法得到的是單源最短路徑,即起點到任意目標點的距離

【lua實現】

 1 local Dijkstra = {}
 2 Dijkstra.__index = Dijkstra
 3 
 4 function Dijkstra.new(g)
 5     local obj = {}
 6     setmetatable(obj, Dijkstra)
 7 
 8     obj:ctor(g)
 9     return obj
10 end
11 
12 function Dijkstra:ctor(g)
13     self.graph = g
14 self.startVertex = nil 15 self.visited = {} 16 self.visitFrom = {} 17 self.distFromStart = {} 18 end 19 20 function Dijkstra:IsReachable(endVertex) 21 return self.distFromStart[endVertex].dist < 9999 22 end 23 24 function Dijkstra:VisitAllReachable(startVertex) 25 self.startVertex = startVertex
26 self.visitFrom = {} 27 self.distFromStart = {} 28 29 for i=1,self.graph:GetVertexCount() do 30 local v = self.graph:GetVertex(i) 31 self.distFromStart[v] = { 32 dist = 9999, 33 used = false, 34 } 35 end 36 37 local distInfo = self.distFromStart[startVertex]
38 distInfo.dist = 0 39 distInfo.used = true 40 41 local v = startVertex 42 while true do 43 local adjList = self.graph:GetAdjacent(v) 44 for i=1,#adjList do 45 local adjVInfo = adjList[i] 46 local oldDist = self.distFromStart[adjVInfo.v].dist 47 local newDist = self.distFromStart[v].dist + adjVInfo.w 48 if newDist < oldDist then 49 self.distFromStart[adjVInfo.v].dist = newDist 50 self.visitFrom[adjVInfo.v] = v 51 end 52 end 53 54 local minDistInfo = nil 55 local minV = nil 56 for i=1,self.graph:GetVertexCount() do 57 local v = self.graph:GetVertex(i) 58 local distInfo = self.distFromStart[v] 59 if not distInfo.used then 60 if nil == minDistInfo or distInfo.dist < minDistInfo.dist then 61 minDistInfo = distInfo 62 minV = v 63 end 64 end 65 end 66 if nil == minDistInfo then --所有都遍歷過了 67 break 68 end 69 70 minDistInfo.used = true 71 v = minV 72 end 73 end 74 75 function Dijkstra:GetDist(endVertex) 76 return self.distFromStart[endVertex].dist 77 end 78 79 function Dijkstra:GetPath(endVertex) 80 if not self:IsReachable(endVertex) then return nil end 81 82 local pathQueue = {} 83 local v = endVertex 84 while v ~= self.startVertex do 85 table.insert(pathQueue, 1, v) 86 v = self.visitFrom[v] 87 end 88 table.insert(pathQueue, 1, v) 89 return pathQueue 90 end

計算下面這張圖的最短路徑:

 1 function CreateGraph()
 2     local g = WeightedGraph.new()
 3     g:AddVertex("A")
 4     g:AddVertex("B")
 5     g:AddVertex("C")
 6     g:AddVertex("D")
 7     g:AddVertex("E")
 8     g:AddVertex("F")
 9     g:AddVertex("G")
10 
11     g:AddEdge("A", "B", 5)
12     g:AddEdge("A", "C", 2)
13     g:AddEdge("B", "D", 1)
14     g:AddEdge("B", "E", 6)
15     g:AddEdge("C", "D", 6)
16     g:AddEdge("C", "F", 8)
17     g:AddEdge("D", "E", 1)
18     g:AddEdge("D", "F", 2)
19     g:AddEdge("E", "G", 7)
20     g:AddEdge("F", "G", 3)
21 
22     --tostring(g)
23     return g
24 end
25 
26 function Test1()
27     local g = CreateGraph()
28     local d = Dijkstra.new(g)
29     d:VisitAllReachable("A")
30     assert(d:IsReachable("B"))
31     assert(d:IsReachable("G"))
32 
33     assert(5 == d:GetDist("B"))
34     assert(2 == d:GetDist("C"))
35     assert(6 == d:GetDist("D"))
36     assert(7 == d:GetDist("E"))
37     assert(8 == d:GetDist("F"))
38     assert(11 == d:GetDist("G"))
39 end
40 Test1()