package Graph
import (
"sort"
"testing"
)
/*
最小生成树算法Prim
1.可以从任意节点出发来寻找最小生成树
2.某个点加入到被选取的点中后,解锁从这个点触发的所有新的边
3.在所有解锁的边中选最小的边,然后看看这个边会不会形成环
4.如果会,不要当前边,继续考察剩下解锁的边中最小的边,重复3
5.如果不会,要当前边,将该边的指向点加入到被选取的点钟,重复2
6.当所有点都被选取,最小生成树就得到了
*/
//最小生成树算法Prim
func PrimMST(graph *Graph) *EdgeSet {
edgesQueue := new(EdgeSet) //解锁的边进入队列
nodeSet := make(map[*Node]struct{}, 0) //哪些点被解锁出来了
edgeSet := make(map[*Edge]struct{}, 0) //已经考虑过的边不重复考虑
result := new(EdgeSet) //依次挑选的边放入结果集
k := 0 //找入度为0的点出发,否则可能会出现出度为0的情况
for k, _ = range graph.Nodes {
if graph.Nodes[k].In == 0 { //应为随便挑选的一个点
break
}
}
//for k,_:=range graph.Nodes{ //防森林
if _, ok := nodeSet[graph.Nodes[k]]; !ok {
nodeSet[graph.Nodes[k]] = struct{}{}
for i, _ := range graph.Nodes[k].Edges {
if _, ok := edgeSet[graph.Nodes[k].Edges[i]]; !ok {
edgeSet[graph.Nodes[k].Edges[i]] = struct{}{}
*edgesQueue = append(*edgesQueue, graph.Nodes[k].Edges[i])
}
}
sort.Sort(edgesQueue)
for len(([]*Edge)(*edgesQueue)) != 0 {
edge := (*edgesQueue)[0] //最小的边
*edgesQueue = (*edgesQueue)[1:] //删掉该边
toNode := edge.To //可能的一个新的点
if _, ok := nodeSet[toNode]; !ok { //不含有的时候,就是新的点
nodeSet[toNode] = struct{}{}
*result = append(*result, edge)
for j, _ := range toNode.Edges {
if _, ok := edgeSet[toNode.Edges[j]]; !ok {
edgeSet[toNode.Edges[j]] = struct{}{}
*edgesQueue = append(*edgesQueue, toNode.Edges[j])
}
}
sort.Sort(edgesQueue)
}
}
}
//break
//}
return result
}
func TestPrim(t *testing.T) {
matrix := [][]int{
{2, 1, 4},
{5, 1, 2},
{3, 1, 5},
{3, 4, 3},
{8, 4, 5},
{9, 5, 6},
{5, 3, 7},
{6, 3, 2},
{2, 2, 6},
{7, 2, 7},
{6, 6, 7},
}
g := CreateGraph(matrix)
for k, v := range *PrimMST(g) {
t.Log("顺序", k+1, "-- 权重:", v.Weight, "从:", v.From.Value, "到:", v.To.Value)
}
}
图——最小生成树算法Prim
于 2021-10-28 19:13:10 首次发布