加权无向图最小生成树-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如下:

 

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