加权无向图最小生成树-Prim和Kruskal法
【最小生成树的前提条件】
# 必须是连通图
# 所有边的权重都不能相同
【参考】
代码实现参考这个: Prim算法和Kruskal算法_日积月累,天道酬勤-CSDN博客
理论知识参考这个: 图的最小生成树 - 智者侬哥 - 博客园 (cnblogs.com)
【Kruskal法】
# 先把所有边按权重排序
# 不断的选权重小的边来组成一颗树, 这棵树的权重和最小, 所以叫最小生成树
1 local Kruskal = {} 2 Kruskal.__index = Kruskal 3 4 function Kruskal.new(g) 5 local obj = {} 6 setmetatable(obj, Kruskal) 7 8 obj:ctor(g) 9 return obj 10 end 11 12 function Kruskal:ctor(g) 13 self.graph = g 14 self.mst = nil 15 self.weight = 0 16 end 17 18 function Kruskal:Build() 19 self.mst = {} 20 self.weight = 0 21 22 local queue = self.graph:GetEdges() 23 local uf = UnionFind.new() 24 function EdgeSort(a, b) 25 return a:GetWeight() <= b:GetWeight() 26 end 27 table.sort(queue, EdgeSort) 28 while #queue > 0 and #self.mst < self.graph:GetVertexCount() - 1 do 29 local minEdge = queue[1] 30 table.remove(queue, 1) 31 32 local v1 = minEdge:GetV1() 33 local v2 = minEdge:GetV2() 34 if not uf:IsConnected(v1, v2) then 35 self.weight = self.weight + minEdge:GetWeight() 36 uf:Union(v1, v2) 37 table.insert(self.mst, minEdge) 38 end 39 end 40 end 41 42 function Kruskal:GetMst() 43 return self.mst 44 end 45 46 function Kruskal:GetWeight() 47 return self.weight 48 end
测试代码:
1 function TestKruskal() 2 local g = CreateGraph() --看加权无向图那片的这个函数 3 4 local k = Kruskal.new(g) 5 k:Build() 6 7 local mst = k:GetMst() 8 print("mst:", #mst) 9 for i=1,#mst do 10 local edge = mst[i] 11 print(edge:GetV1(), edge:GetV2(), edge:GetWeight()) 12 end 13 end 14 TestKruskal()
【Prim法】
# 选一个顶点, 获取所有与他连接的边, 获得权重最小的边, 加入最小生成树
# 再取最小边的另一个点, 重复第1步
1 local Prim = {} 2 Prim.__index = Prim 3 4 function Prim.new(g) 5 local obj = {} 6 setmetatable(obj, Prim) 7 8 obj:ctor(g) 9 return obj 10 end 11 12 function Prim:ctor(g) 13 self.graph = g 14 self.mst = nil 15 self.weight = 0 16 end 17 18 function Prim:Build(startVertex) 19 self.mst = {} 20 self.weight = 0 21 local marked = {} 22 local queue = {} 23 24 function EdgeSort(a, b) 25 return a:GetWeight() <= b:GetWeight() 26 end 27 28 function AddAdjacentEdges(v) --添加所有与顶点连接的边 29 marked[v] = true 30 local edgeList = self.graph:GetAdjacent(v) 31 for i=1,#edgeList do 32 local edge = edgeList[i] 33 table.insert(queue, edge) 34 end 35 table.sort(queue, EdgeSort) 36 end 37 AddAdjacentEdges(startVertex) 38 39 while #queue > 0 do 40 local minEdge = queue[1] 41 table.remove(queue, 1) 42 43 local v2 = minEdge:GetV2() 44 if not marked[v2] then 45 table.insert(self.mst, minEdge) 46 self.weight = self.weight + minEdge:GetWeight() 47 48 AddAdjacentEdges(v2) 49 end 50 end 51 end 52 53 function Prim:GetMst() 54 return self.mst 55 end 56 57 function Prim:GetWeight() 58 return self.weight 59 end
测试代码:
1 function TestPrim1() 2 local g = CreateGraph() --看加权无向图那篇的这个函数 3 4 local prim = Prim.new(g) 5 prim:Build("0") 6 7 local mst = prim:GetMst() 8 for i=1,#mst do 9 local edge = mst[i] 10 print(edge:GetV1(), edge:GetV2(), edge:GetWeight()) 11 end 12 end 13 TestPrim1()
上面两个用到的Graph如下: