Minimum generation of graphs prim and knuskar

Posted by cjl on Wed, 12 Jan 2022 10:41:29 +0100

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

  1. 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.

  2. 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)

  3. 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

  4. Scan:
    Scan all unselected nodes (points with false value in the set value) and find the point with the lowest minDist value p

  5. 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)

  6. 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

  7. Cycle execution 4 Scanning, 5 Add, 6 Update, all the way to seleted

  8. 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

Topics: data structure