基本概念
图(Graph)是一种复杂的非线性结构,在图结构中,每个元素都可以有零个或多个前驱,也可以有零个或多个后继,也就是说,元素之间的关系是任意的。
常用术语
术语 | 含义 |
---|---|
顶点 | 图中的某个结点 |
边 | 顶点之间连线 |
相邻顶点 | 由同一条边连接在一起的顶点 |
度 | 一个顶点的相邻顶点个数 |
简单路径 | 由一个顶点到另一个顶点的路线,且没有重复经过顶点 |
回路 | 出发点和结束点都是同一个顶点 |
无向图 | 图中所有的边都没有方向 |
有向图 | 图中所有的边都有方向 |
无权图 | 图中的边没有权重值 |
有权图 | 图中的边带有一定的权重值 |
结构及实现
type Node struct {
Value, In, Out int // 值,入度,出度
Nexts []*Node
Edges []*Edge
}
type Edge struct {
Weight int
From *Node
To *Node
}
type Graph struct {
Nodes map[int]*Node
Edges map[*Edge]struct{}
}
// 从别的图结构转成自己的结构,可以根据适当减少字段如出入度,权重
func CreateGraph(matrix [][]int) Graph {
graph := Graph{}
for _, v := range matrix {
weight := v[0]
from := v[1]
to := v[2]
if _, ok := graph.Nodes[from]; !ok {
graph.Nodes[from] = &Node{
Value: from,
}
}
if _, ok := graph.Nodes[to]; !ok {
graph.Nodes[to] = &Node{
Value: to,
}
}
fromNode := graph.Nodes[from]
toNode := graph.Nodes[to]
edge := &Edge{
Weight: weight,
From: fromNode,
To: toNode,
}
fromNode.Out++
toNode.In++
fromNode.Nexts = append(fromNode.Nexts, toNode)
fromNode.Edges = append(fromNode.Edges, edge)
graph.Edges[edge] = struct{}{}
}
return graph
}
图的深度优先遍历
从一个顶点开始,沿着一条路径一直搜索,直到到达该路径的最后一个结点,然后回退到之前经过但未搜索过的路径继续搜索,直到所有路径和结点都被搜索完毕
func GraphDFS(start *Node) {
if start == nil {
return
}
stack := stack.NewStack[*Node]()
set := map[*Node]struct{}{}
set[start] = struct{}{}
stack.Push(start)
fmt.Print(start.Value)
for !stack.IsEmpty() {
cur, _ := stack.Pop()
for _, v := range cur.Nexts {
if _, ok := set[v]; !ok {
stack.Push(cur)
stack.Push(v)
fmt.Print(v.Value)
set[v] = struct{}{}
break
}
}
}
}
图的广度优先遍历
类似于图的层次遍历,它的基本思想是:首先访问起始顶点v,然后选取v的所有邻接点进行访问,再依次对v的邻接点相邻接的所有点进行访问,以此类推,直到所有顶点都被访问过为止
func GraphBFS(start *Node) {
if start == nil {
return
}
queue := queue.NewQueue[*Node]()
set := map[*Node]struct{}{}
queue.Push(start)
set[start] = struct{}{}
for !queue.IsEmpty() {
cur := queue.Pop()
fmt.Print(cur.Value)
for _, v := range cur.Nexts {
if _, ok := set[v]; !ok {
queue.Push(v)
set[v] = struct{}{}
}
}
}
}