2019独角兽企业重金招聘Python工程师标准>>>
graph.go
package maps
import (
"fmt"
)
/*
涉及对象:
1. 顶点(Node): 顶点内容、是否访问
2. 边(Edge): 顶点A-B,权重,是否访问
3. 图(map): 容量、邻接矩阵、当前顶点个数、顶点集合、边集合
涉及概念:
顶点集合数量 = 容量
边集合数量 = 顶点集合数量 - 1
邻接矩阵大小 = 容量 ^ 2
*/
// Node struct.
type Node struct {
Data rune
IsVisited bool
}
// Edge struct.
type Edge struct {
NodeIndexA int
NodeIndexB int
WeightValue int
IsVisited bool
}
// CMap struct.
type CMap struct {
Capacity int // 容量
Matrix []int // 邻接矩阵
NodeCount int // 节点个数
NodeArray []Node // 节点数据
Edge []Edge // 边数据
}
// CreateEdge .
func CreateEdge(nodeIndexA, nodeIndexB, weightValue int) *Edge {
return &Edge{
NodeIndexA: nodeIndexA,
NodeIndexB: nodeIndexB,
WeightValue: weightValue,
IsVisited: false,
}
}
// CreateCMap impl.
func CreateCMap(capacity int) *CMap {
return &CMap{
Capacity: capacity,
Matrix: make([]int, capacity*capacity),
NodeCount: 0,
NodeArray: make([]Node, capacity),
Edge: make([]Edge, capacity-1),
}
}
// AddNode impl.
func (cmap *CMap) AddNode(node *Node) bool {
if node == nil {
return false
}
cmap.NodeArray[cmap.NodeCount].Data = node.Data
cmap.NodeCount++
return true
}
// ResetNode impl
func (cmap *CMap) ResetNode() {
for i := 0; i < len(cmap.NodeArray); i++ {
cmap.NodeArray[i].IsVisited = false
}
}
// SetValueToMatrixForDirectedGraph impl.
func (cmap *CMap) SetValueToMatrixForDirectedGraph(row, col, val int) bool {
if row <= 0 || row >= cmap.Capacity {
return false
}
if col < 0 || col >= cmap.Capacity {
return false
}
cmap.Matrix[row*cmap.Capacity+col] = val
return true
}
// SetValueToMatrixForUnDirectedGraph impl.
func (cmap *CMap) SetValueToMatrixForUnDirectedGraph(row, col, val int) bool {
if row < 0 || row >= cmap.Capacity {
return false
}
if col < 0 || col >= cmap.Capacity {
return false
}
cmap.Matrix[row*cmap.Capacity+col] = val
cmap.Matrix[col*cmap.Capacity+row] = val
return true
}
// GetWeightValueFromMatrix impl
func (cmap *CMap) GetWeightValueFromMatrix(row, col int) int {
if row < 0 || row >= cmap.Capacity {
return 0
}
if col < 0 || col >= cmap.Capacity {
return 0
}
return cmap.Matrix[row*cmap.Capacity+col]
}
// PrinMatrix impl.
func (cmap *CMap) PrinMatrix() {
for i := 0; i < cmap.Capacity; i++ {
for k := 0; k < cmap.Capacity; k++ {
fmt.Printf("%d\t", (cmap.Matrix[i*cmap.Capacity+k]))
}
fmt.Println()
}
}
// DepthFirstTraverse impl.
func (cmap *CMap) DepthFirstTraverse(nodeIndex int) {
fmt.Print(string(cmap.NodeArray[nodeIndex].Data), " ")
cmap.NodeArray[nodeIndex].IsVisited = true
for i := 0; i < cmap.Capacity; i++ {
value := cmap.GetWeightValueFromMatrix(nodeIndex, i)
if value != 0 {
if !cmap.NodeArray[i].IsVisited {
cmap.DepthFirstTraverse(i)
}
}
}
}
// BreadthFirstTraverse impl
func (cmap *CMap) BreadthFirstTraverse(nodeIndex int) {
fmt.Println(cmap.NodeArray[nodeIndex].Data, " ")
cmap.NodeArray[nodeIndex].IsVisited = true
var vector []int
vector = append(vector, nodeIndex)
cmap.BreadthFirstTraverseImpl(vector)
}
// BreadthFirstTraverseImpl .
func (cmap *CMap) BreadthFirstTraverseImpl(preVector []int) {
var vector []int
for j := 0; j < len(preVector); j++ {
for i := 0; i < cmap.Capacity; i++ {
value := cmap.GetWeightValueFromMatrix(preVector[j], i)
if value != 0 {
if !cmap.NodeArray[i].IsVisited {
fmt.Print(string(cmap.NodeArray[i].Data), " ")
cmap.NodeArray[i].IsVisited = true
vector = append(vector, i)
}
}
}
}
if len(vector) > 0 {
cmap.BreadthFirstTraverseImpl(vector)
}
}
// PrimTree (最小生成树 - 普里姆).
// 1. 选择一个顶点,放入已选顶点集合
// 2. 找到顶点对应的边集合,放入待选择集合
// 3. 找到最小权重的边,放入已选边集合
// 4. 找到最小权重边的另外一个顶点B,放入已选顶点集合
// 5. 找到顶点B对应的边集合,放入待选择集合
// 6. 找到最小权重的边,放入已选边集合
// 7. ...
func (cmap *CMap) PrimTree(nodeIndex int) {
value := 0
edgeCount := 0
var nodes []int
var edges []Edge
nodes = append(nodes, nodeIndex)
cmap.NodeArray[nodeIndex].IsVisited = true
fmt.Println(string(cmap.NodeArray[nodeIndex].Data))
for edgeCount < cmap.Capacity-1 {
temp := nodes[len(nodes)-1]
nodes = nodes[:len(nodes)-1]
// 1. 找到所有与顶点temp对应的边
for i := 0; i < cmap.Capacity; i++ {
value = cmap.GetWeightValueFromMatrix(temp, i)
if value != 0 {
if !cmap.NodeArray[i].IsVisited {
edge := Edge{
NodeIndexA: temp,
NodeIndexB: i,
WeightValue: value,
}
edges = append(edges, edge)
}
}
}
// 2. 从可选边集合找到最小的边
minEdgeIndex := getMinEdge(edges)
edges[minEdgeIndex].IsVisited = true
cmap.Edge[edgeCount] = edges[minEdgeIndex]
edgeCount++
fmt.Print(edges[minEdgeIndex].NodeIndexA, "---", edges[minEdgeIndex].NodeIndexB, " ")
fmt.Println(edges[minEdgeIndex].WeightValue)
// 3. 找出下一个顶点并放入集合
nextNodeIndex := edges[minEdgeIndex].NodeIndexB
nodes = append(nodes, nextNodeIndex)
cmap.NodeArray[nextNodeIndex].IsVisited = true
fmt.Println(string(cmap.NodeArray[nextNodeIndex].Data))
}
}
// KruskalTree (最小生成树 - 克鲁斯卡尔)
// 1. 找到所有的边,放入集合SetA
// 2. 选择权重最小的边,并将边放入数组
// 3. 查找权重最小边涉及的顶点(顶点a-b),并将顶点放入数组
// 4. 查找顶点a和b所在的集合
// 5. 根据顶点a和b所在的集合进行如下逻辑处理:
// 1). 如顶点a和b在都不在集合中,则新建集合set,并将顶点a和b放入set集合
// 2). 如顶点a(b)在集合set中,b(a)不在集合中, 则将b(a)放入集合a(b)中
// 3). 如顶点a和b在不同的集合,则将b集合合并到a集合
// 4). 如顶点a和b在同一集合,则产生回路,不做处理
// 6. 循环步骤2-5【当边未搜索完时】
func (cmap *CMap) KruskalTree() {
var edgeCount int
// 定义存放节点集合的数组
var nodeSets [][]int
// 一、取出所有的边
var edges []Edge
for i := 0; i < cmap.Capacity; i++ {
for k := i + 1; k < cmap.Capacity; k++ {
value := cmap.GetWeightValueFromMatrix(i, k)
if value != 0 {
edge := Edge{
NodeIndexA: i,
NodeIndexB: k,
WeightValue: value,
}
edges = append(edges, edge)
}
}
}
// 二、从所有边去除组成最小生成树的边
// 1. 找到算法的结束条件
for edgeCount < cmap.Capacity-1 {
// 2. 从边集合找出最小边
minEdgeIndex := getMinEdge(edges)
edges[minEdgeIndex].IsVisited = true
// 3. 找出最小边连接的点
nodeAIndex := edges[minEdgeIndex].NodeIndexA
nodeBIndex := edges[minEdgeIndex].NodeIndexB
nodeAIsInSet := false
nodeBIsInSet := false
nodeAInSetLabel := -1
nodeBInSetLabel := -1
// 4. 找出A点所在的集合
for i := 0; i < len(nodeSets); i++ {
nodeAIsInSet = isInSet(nodeSets[i], nodeAIndex)
if nodeAIsInSet {
nodeAInSetLabel = i
}
}
// 找出B点所在的集合
for i := 0; i < len(nodeSets); i++ {
nodeBIsInSet = isInSet(nodeSets[i], nodeBIndex)
if nodeBIsInSet {
nodeBInSetLabel = i
}
}
// 5. 根据点所在集合的不同做出不同的处理
if nodeAInSetLabel == -1 && nodeBInSetLabel == -1 {
var newEdges []int
newEdges = append(newEdges, nodeAIndex, nodeBIndex)
nodeSets = append(nodeSets, newEdges)
} else if nodeAInSetLabel == -1 && nodeBInSetLabel != -1 {
nodeSets[nodeBInSetLabel] = append(nodeSets[nodeBInSetLabel], nodeAIndex)
} else if nodeAInSetLabel != -1 && nodeBInSetLabel == -1 {
nodeSets[nodeAInSetLabel] = append(nodeSets[nodeAInSetLabel], nodeBIndex)
} else if nodeAInSetLabel != -1 && nodeBInSetLabel != -1 {
mergeNodeSet(&nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel])
nodeSets = append(nodeSets[:nodeBInSetLabel], nodeSets[nodeBInSetLabel+1:]...)
} else if nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel {
continue
}
cmap.Edge[edgeCount] = edges[minEdgeIndex]
edgeCount++
fmt.Print(edges[minEdgeIndex].NodeIndexA, "--", edges[minEdgeIndex].NodeIndexB, " ")
fmt.Println(string(edges[minEdgeIndex].WeightValue))
}
}
// 获取最小的边索引
func getMinEdge(edges []Edge) int {
minWeight := 0
edgeIndex := 0
i := 0
for ; i < len(edges); i++ {
if !edges[i].IsVisited {
minWeight = edges[i].WeightValue
edgeIndex = i
break
}
}
if minWeight == 0 {
return -1
}
for ; i < len(edges); i++ {
if !edges[i].IsVisited {
if edges[i].WeightValue < minWeight {
minWeight = edges[i].WeightValue
edgeIndex = i
}
}
}
return edgeIndex
}
// 是否在集合中
func isInSet(sets []int, target int) bool {
for i := 0; i < len(sets); i++ {
if sets[i] == target {
return true
}
}
return false
}
// 合并node
func mergeNodeSet(nodeSetA *[]int, nodeSetB []int) {
*nodeSetA = append(*nodeSetA, nodeSetB...)
}
graph_test.go
package maps
import "testing"
func TestCMap(t *testing.T) {
cmap := CreateCMap(8)
nodeA := &Node{Data: 'A'}
nodeB := &Node{Data: 'B'}
nodeC := &Node{Data: 'C'}
nodeD := &Node{Data: 'D'}
nodeE := &Node{Data: 'E'}
nodeF := &Node{Data: 'F'}
cmap.AddNode(nodeA)
cmap.AddNode(nodeB)
cmap.AddNode(nodeC)
cmap.AddNode(nodeD)
cmap.AddNode(nodeE)
cmap.AddNode(nodeF)
cmap.SetValueToMatrixForUnDirectedGraph(0, 1, 6)
cmap.SetValueToMatrixForUnDirectedGraph(0, 4, 5)
cmap.SetValueToMatrixForUnDirectedGraph(0, 5, 1)
cmap.SetValueToMatrixForUnDirectedGraph(1, 2, 3)
cmap.SetValueToMatrixForUnDirectedGraph(1, 5, 2)
cmap.SetValueToMatrixForUnDirectedGraph(2, 5, 8)
cmap.SetValueToMatrixForUnDirectedGraph(2, 3, 7)
cmap.SetValueToMatrixForUnDirectedGraph(3, 5, 4)
// cmap.PrinMatrix()
// cmap.DepthFirstTraverse(0)
// cmap.BreadthFirstTraverse(0)
// cmap.KruskalTree()
cmap.PrimTree(0)
}