1, Code implementation of knuskar
1. Implementation of adjacency matrix of graph
mgraph.go
package graph import "errors" const MaxSize = 20 type MGraph struct { Edges [MaxSize][MaxSize]int EdgeNum int Nodes []string Indexs map[string]int } type Edge struct { NodeStart, NodeEnd string Val int } func NewMGraph() MGraph { var g MGraph for k, v := range g.Edges { for kk, _ := range v { g.Edges[k][kk] = -1 } } g.Indexs = make(map[string]int) return g } func (g *MGraph) AddNode(nodeName string) error { if g.Indexs == nil { return errors.New("Is not a valid graph") } if _, ok := g.Indexs[nodeName]; ok { return errors.New("This node has been added") } g.Indexs[nodeName] = len(g.Nodes) g.Nodes = append(g.Nodes, nodeName) return nil } func (g *MGraph) AddEdge(nodeName1, nodeName2 string, val int) error { if _, ok := g.Indexs[nodeName1]; !ok { return errors.New("Node does not exist:" + nodeName1) } if _, ok := g.Indexs[nodeName2]; !ok { return errors.New("Node does not exist:" + nodeName2) } if g.Edges[g.Indexs[nodeName1]][g.Indexs[nodeName2]] != -1 { return errors.New("Edge already exists") } g.Edges[g.Indexs[nodeName1]][g.Indexs[nodeName2]] = val g.Edges[g.Indexs[nodeName2]][g.Indexs[nodeName1]] = val g.EdgeNum++ return nil } func (g *MGraph) GetEdgeList() []Edge { var edgeList []Edge for i := 0; i < len(g.Nodes); i++ { for j := 0; j < i; j++ { if g.Edges[i][j] >= 0 { edgeList = append( edgeList, Edge{NodeStart: g.Nodes[i], NodeEnd: g.Nodes[j], Val: g.Edges[i][j]}, ) } } } return edgeList }
2. Knuskar implementation code
Kruskal.go
package minimum_spanning_tree import ( "fmt" "gitee.com/gudongkun/datestruct/dataStructures/graph" "gitee.com/gudongkun/datestruct/dataStructures/unionfind" "sort" ) func GetExGraph() *graph.MGraph { g := graph.NewMGraph() g.AddNode("A") g.AddNode("B") g.AddNode("C") g.AddNode("D") g.AddNode("E") g.AddNode("F") g.AddNode("G") g.AddNode("H") g.AddNode("I") g.AddNode("J") g.AddEdge("A", "B", 5) g.AddEdge("A", "D", 9) g.AddEdge("A", "E", 1) g.AddEdge("B", "D", 2) g.AddEdge("B", "C", 4) g.AddEdge("C", "H", 4) g.AddEdge("C", "I", 1) g.AddEdge("C", "J", 8) g.AddEdge("D", "H", 2) g.AddEdge("D", "G", 11) g.AddEdge("D", "F", 5) g.AddEdge("D", "E", 2) g.AddEdge("E", "F", 1) g.AddEdge("F", "G", 7) g.AddEdge("G", "H", 1) g.AddEdge("G", "I", 4) g.AddEdge("H", "I", 6) g.AddEdge("I", "J", 0) return &g } func Kruskal() []graph.Edge { var treeEdge []graph.Edge g := GetExGraph() originEdge := g.GetEdgeList() //1. Sort edges sort.SliceStable(originEdge, func(i, j int) bool { return originEdge[i].Val < originEdge[j].Val }) //2. Build and query set union := unionfind.NewUnionFind(g.Nodes) for _, v := range originEdge { if union.IsConnected(v.NodeStart, v.NodeEnd) { continue } treeEdge = append(treeEdge, v) union.Unify(v.NodeStart, v.NodeEnd) if union.Groups() == 1 { break } } if union.Groups()>1 { fmt.Println("Non connected graph",union) } else { fmt.Println("The spanning tree is:",treeEdge) } return treeEdge }
3. Test code
Kruskal_test.go
package minimum_spanning_tree import "testing" func TestGetExGraph(t *testing.T) { g := GetExGraph() if g.EdgeNum != 18 { t.Error("GetExGraph Error") } if len(g.GetEdgeList()) != 18 { t.Error("GetEdgeList Error") } } func TestKruskal(t *testing.T) { Kruskal() }
2, Prim algorithm for Graphs
Algorithm idea: select any vertex in the graph as a tree, select the shortest path connected with the vertex, add the path to the tree, and add the edge to the selected edge. At this time, a tree with two edges is obtained. Then select the shortest edge from the edges connected to the tree, add another vertex to the tree, add the edge to the selected edge, and so on until all vertices are added to the tree. The resulting tree is the minimum spanning tree.
1. Algorithm description
-
Initialize three arrays
Completed: Records whether the node has been regenerated into a tree. The subscript represents the node and is initially false;
minDist: records the weight size of the minimum weight edge from this point to the set of selected vertices at a certain time. The initial value is infinity
prev: records the subscript of the parent element in the vertex connection tree. The initial value is - 1, which means no vertices are connected. -
Initialize any vertex s operation:
Arbitrarily select a vertex s and add it to the spanning tree (seleted[s] = true);
Point s has entered the spanning tree, and the distance to the spanning tree is meaningless. It is set to - 1 (minDist[s] = -1);
Initial vertex has no parent element (prev[s] = -1) -
Update first vertex s operation:
Scan all edges connected to vertex s (cp, another vertex, the weight value of edge v). If the distance from the vertex to this store is smaller than the second in minDist, minDist [cp] = v, prev [cp] = s -
Scan:
Scan all unselected nodes (points with false value in the set value) and find the point with the lowest minDist value p -
add to:
Add point p to spanning tree (completed [p] = true)
The distance from the point p to the tree, which is meaningless, is set to - 1 (minDist[p] = -1) -
to update:
Scan all edges connected to vertex p (the other vertex of cp edge, the weight value of v edge). If the distance from the vertex to this store is smaller than the second in minDist, minDist [cp] = v, prev [cp] = p -
Cycle execution 4 Scanning, 5 Add, 6 Update, all the way to seleted
-
All points become true,
Through the prev array, we can push down the edge of the minimum spanning tree.
2. Graphic description
Please refer to: https://www.bilibili.com/video/BV1Eb41177d1
3. Algorithm code implementation
(1) Figure adding the interface for obtaining adjacent nodes
func (g *MGraph) GetConnectedEdges(ele string) []Edge { var edgeList []Edge k := g.Indexs[ele] for i := 0; i < len(g.Nodes); i++ { if g.Edges[k][i] >= 0 { edgeList = append( edgeList, Edge{NodeStart: g.Nodes[k], NodeEnd: g.Nodes[i], Val: g.Edges[k][i]}, ) } } return edgeList }
(2) Prim algorithm
prim.go
package minimum_spanning_tree import "fmt" func Prim() map[string]string { g := GetExGraph() //initialization selected := make(map[string]bool) minDist := make(map[string]int) prev := make(map[string]string) for _, node := range g.Nodes { selected[node] = false minDist[node] = 9999999 } // Add first vertex selected[g.Nodes[0]] = true minDist[g.Nodes[0]] = -1 prev[g.Nodes[0]] = "root" // Update first vertex for _, edge := range g.GetConnectedEdges(g.Nodes[0]) { if minDist[edge.NodeEnd] > edge.Val { minDist[edge.NodeEnd] = edge.Val prev[edge.NodeEnd] = g.Nodes[0] } } for { // scan operation minK := "" minV := 9999999 for k, v := range selected { if v { continue } if minDist[k] < minV { //Select the point with the smallest distance among the unselected points minK = k minV = minDist[k] } } if minK == "" { break } //add operation selected[minK] = true // minK set to selected minDist[minK] = -1 // Distance failure of minK //The update operation updates the distance from the unselected point to the selected point for _, edge := range g.GetConnectedEdges(minK) { if minDist[edge.NodeEnd] > edge.Val { minDist[edge.NodeEnd] = edge.Val prev[edge.NodeEnd] = minK } } } fmt.Println(prev, len(prev)) return prev }
(3) Prim algorithm unit test
package minimum_spanning_tree import "testing" func TestPrim(t *testing.T) { prev := Prim() if len(prev) != 10 { t.Error(prev) } }
(4) Complete code of modified figure
package graph import "errors" const MaxSize = 20 type MGraph struct { Edges [MaxSize][MaxSize]int EdgeNum int Nodes []string Indexs map[string]int } type Edge struct { NodeStart, NodeEnd string Val int } func NewMGraph() MGraph { var g MGraph for k, v := range g.Edges { for kk, _ := range v { g.Edges[k][kk] = -1 } } g.Indexs = make(map[string]int) return g } func (g *MGraph) AddNode(nodeName string) error { if g.Indexs == nil { return errors.New("Is not a valid graph") } if _, ok := g.Indexs[nodeName]; ok { return errors.New("This node has been added") } g.Indexs[nodeName] = len(g.Nodes) g.Nodes = append(g.Nodes, nodeName) return nil } func (g *MGraph) AddEdge(nodeName1, nodeName2 string, val int) error { if _, ok := g.Indexs[nodeName1]; !ok { return errors.New("Node does not exist:" + nodeName1) } if _, ok := g.Indexs[nodeName2]; !ok { return errors.New("Node does not exist:" + nodeName2) } if g.Edges[g.Indexs[nodeName1]][g.Indexs[nodeName2]] != -1 { return errors.New("Edge already exists") } g.Edges[g.Indexs[nodeName1]][g.Indexs[nodeName2]] = val g.Edges[g.Indexs[nodeName2]][g.Indexs[nodeName1]] = val g.EdgeNum++ return nil } func (g *MGraph) GetEdgeList() []Edge { var edgeList []Edge for i := 0; i < len(g.Nodes); i++ { for j := 0; j < i; j++ { if g.Edges[i][j] >= 0 { edgeList = append( edgeList, Edge{NodeStart: g.Nodes[i], NodeEnd: g.Nodes[j], Val: g.Edges[i][j]}, ) } } } return edgeList } func (g *MGraph) GetConnectedEdges(ele string) []Edge { var edgeList []Edge k := g.Indexs[ele] for i := 0; i < len(g.Nodes); i++ { if g.Edges[k][i] >= 0 { edgeList = append( edgeList, Edge{NodeStart: g.Nodes[k], NodeEnd: g.Nodes[i], Val: g.Edges[k][i]}, ) } } return edgeList }
git connection of relevant codes:
https://gitee.com/gudongkun/datestruct