Dijkstra计算加权图的最短路径

# 加权的有向,无向图都可以

# Dijkstra是A* 算法的特例

 

【理论知识的,可以参考】

漫画:图的最短路径问题_~~ LINUX ~~-CSDN博客

图论算法——最短路径算法_日积月累,天道酬勤-CSDN博客

 

该算法得到的是单源最短路径,即起点到任意目标点的距离

【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.visitFrom = {} --点之间的遍历关系, key:当前遍历点, value:上一个遍历点
16     self.distFromStart = {} --从起始点到该点的距离
17 end
18 
19 function Dijkstra:IsReachable(endVertex)
20     return self.distFromStart[endVertex].dist < 9999
21 end
22 
23 function Dijkstra:VisitAllReachable(startVertex)
24     self.startVertex = startVertex
25     self.visitFrom = {}
26     self.distFromStart = {}
27 
28     for i=1,self.graph:GetVertexCount() do
29         local v = self.graph:GetVertex(i)
30         self.distFromStart[v] = {
31             dist = 9999,
32             used = false,
33         }
34     end
35 
36     local distInfo = self.distFromStart[startVertex]
37     distInfo.dist = 0
38     distInfo.used = true
39 
40     local v = startVertex
41     while true do
42         local adjList = self.graph:GetAdjacent(v)
43         for i=1,#adjList do
44             local edge = adjList[i]
45             local v2 = edge:GetV2()
46             local oldDist = self.distFromStart[v2].dist
47             local newDist = self.distFromStart[v].dist + edge:GetWeight()
48             if newDist < oldDist then
49                 self.distFromStart[v2].dist = newDist
50                 self.visitFrom[v2] = v
51             end
52         end
53 
54         --从距离最小的点继续往后遍历
55         --从ta开始过1次, 后面将不会再从ta开始
56         local minDistInfo = nil
57         local minV = nil
58         for i=1,self.graph:GetVertexCount() do
59             local v = self.graph:GetVertex(i)
60             local distInfo = self.distFromStart[v]
61             if not distInfo.used then
62                 if nil == minDistInfo or distInfo.dist < minDistInfo.dist then
63                     minDistInfo = distInfo
64                     minV = v
65                 end
66             end
67         end
68         if nil == minDistInfo then --所有都遍历过了
69             break
70         end
71 
72         minDistInfo.used = true
73         v = minV
74     end
75 end
76 
77 function Dijkstra:GetDist(endVertex)
78     return self.distFromStart[endVertex].dist
79 end
80 
81 function Dijkstra:GetPath(endVertex)
82     if not self:IsReachable(endVertex) then return nil end
83 
84     local pathQueue = {}
85     local v = endVertex
86     while v ~= self.startVertex do
87         table.insert(pathQueue, 1, v)
88         v = self.visitFrom[v]
89     end
90     table.insert(pathQueue, 1, v)
91     return pathQueue
92 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()

 

posted @ 2022-03-10 23:46  yanghui01  阅读(124)  评论(0编辑  收藏  举报