无向图-邻接表方式
【要看理论知识的,可以参考这边】
无向图的邻接链表实现
无向图的深度优先搜索和广度优先搜索
漫画:图的 “最短路径” 问题
【lua实现】
1 local Graph = {} 2 Graph.__index = Graph 3 4 ---无向图 5 function Graph.new() 6 local obj = {} 7 setmetatable(obj, Graph) 8 9 obj:ctor() 10 return obj 11 end 12 13 function Graph:ctor() 14 self.adjacent = {} 15 self.edgeCount = 0 16 self.vertexList = {} 17 end 18 19 function Graph:GetVertexCount() 20 return #self.vertexList 21 end 22 23 function Graph:GetEdgeCount() 24 return self.edgeCount 25 end 26 27 function Graph:AddVertex(v) 28 local list = self.adjacent[v] 29 if nil == list then 30 list = {} 31 self.adjacent[v] = list 32 table.insert(self.vertexList, v) 33 else 34 --顶点已存在 35 end 36 end 37 38 function Graph:AddEdge(v1, v2) 39 local list1 = self.adjacent[v1] 40 local list2 = self.adjacent[v2] 41 if nil == list1 or nil == list2 then 42 return --顶点不存在 43 end 44 45 table.insert(list1, v2) --最好判断下在list中是否已存在 46 table.insert(list2, v1) 47 self.edgeCount = self.edgeCount + 1 48 end 49 50 function Graph:GetAdjacent(v) 51 return self.adjacent[v] 52 end 53 54 function Graph:__tostring() 55 print("-----Graph") 56 for i=1,#self.vertexList do 57 local v = self.vertexList[i] 58 local adjList = self.adjacent[v] 59 print(v, "-->", table.concat(adjList, ", ")) 60 end 61 print("-----") 62 end
1 function CreateGraph() 2 local g = Graph.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") 12 g:AddEdge("A", "C") 13 g:AddEdge("B", "D") 14 g:AddEdge("B", "E") 15 g:AddEdge("C", "D") 16 g:AddEdge("C", "F") 17 g:AddEdge("D", "E") 18 g:AddEdge("D", "F") 19 g:AddEdge("E", "G") 20 g:AddEdge("F", "G") 21 22 print("v ct: ", g:GetVertexCount()) 23 print("edge ct:", g:GetEdgeCount()) 24 tostring(g) 25 return g 26 end
上面的代码会创建出这样一张图
【深度优先搜索】
# 这边使用了递归来实现
# 用途:会把某个点的所有可达顶点都走一遍,即可以通过它来确定两个点之间是否可达
1 function TestDfs1() 2 local visited = {} 3 4 function Dfs1(g, vertex) 5 print(vertex) 6 7 visited[vertex] = true 8 local list = g:GetAdjacent(vertex) 9 for i=1,#list do 10 local adjV = list[i] 11 if not visited[adjV] then 12 Dfs1(g, adjV) 13 end 14 end 15 end 16 17 local g = CreateGraph() 18 Dfs1(g, "A") 19 end 20 TestDfs1()
【广度优先搜索】
# 一般会借助一个队列来实现
# 用途1:会把某个点的所有可达顶点都走一遍,即可以知道两个点之间是否可达
# 用途2:可以算出点A到点B的最短路径
1 function TestBfs1() 2 local edgeFrom = {} 3 4 function Bfs1(g, vertex) 5 local visited = {} 6 local queue = {} 7 visited[vertex] = true --加入queue就要设为visited 8 table.insert(queue, vertex) 9 10 while #queue > 0 do 11 local v = queue[1] 12 print("---", table.concat(queue, ", ")) 13 print(v) 14 table.remove(queue, 1) 15 16 local list = g:GetAdjacent(v) 17 for i=1,#list do 18 local adjV = list[i] 19 if not visited[adjV] then 20 visited[adjV] = true --加入queue就要设为visited 21 edgeFrom[adjV] = v 22 table.insert(queue, adjV) 23 end 24 end 25 end 26 end 27 28 local g = CreateGraph() 29 Bfs1(g, "A") 30 31 local path = {} 32 local target = "G" 33 local start = "A" 34 local v = target 35 while v ~= start do 36 table.insert(path, v) 37 v = edgeFrom[v] 38 end 39 table.insert(path, v) 40 print("shortest path: ", table.concat(path)) 41 end 42 TestBfs1()