Dijkstra計算加權無向圖的最短路徑
阿新 • • 發佈:2022-02-27
【理論知識的,可以參考】
該演算法得到的是單源最短路徑,即起點到任意目標點的距離
【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 = g14 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 = startVertex26 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()