forked from krahets/hello-algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(graph): add go codes (krahets#314)
* feat(graph): add go codes * feat(go/graph): add graph_adjacency_list * doc(graph): add go codes * fix(graph): fix go codes * Update graph_adjacency_matrix_test.go --------- Co-authored-by: Yudong Jin <[email protected]>
- Loading branch information
Showing
6 changed files
with
469 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,4 @@ | |
!*.* | ||
# Unignore all dirs | ||
!*/ | ||
|
||
*.dSYM/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// File: graph_adjacency_list.go | ||
// Created Time: 2023-01-31 | ||
// Author: Reanon ([email protected]) | ||
|
||
package chapter_graph | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
/* 顶点类 */ | ||
type vertex struct { | ||
val int | ||
} | ||
|
||
func newVertex(val int) vertex { | ||
return vertex{ | ||
val: val, | ||
} | ||
} | ||
|
||
/* 基于邻接表实现的无向图类 */ | ||
type graphAdjList struct { | ||
// 请注意,vertices 和 adjList 中存储的都是 Vertex 对象 | ||
// 邻接表(使用哈希表实现), 使用哈希表模拟集合 | ||
adjList map[vertex]map[vertex]struct{} | ||
} | ||
|
||
/* 构造函数 */ | ||
func newGraphAdjList(edges [][]vertex) *graphAdjList { | ||
g := &graphAdjList{ | ||
adjList: make(map[vertex]map[vertex]struct{}), | ||
} | ||
// 添加所有顶点和边 | ||
for _, edge := range edges { | ||
g.addVertex(edge[0]) | ||
g.addVertex(edge[1]) | ||
g.addEdge(edge[0], edge[1]) | ||
} | ||
return g | ||
} | ||
|
||
/* 获取顶点数量 */ | ||
func (g *graphAdjList) size() int { | ||
return len(g.adjList) | ||
} | ||
|
||
/* 添加边 */ | ||
func (g *graphAdjList) addEdge(vet1 vertex, vet2 vertex) { | ||
_, ok1 := g.adjList[vet1] | ||
_, ok2 := g.adjList[vet2] | ||
if !ok1 || !ok2 || vet1 == vet2 { | ||
panic("error") | ||
} | ||
// 添加边 vet1 - vet2, 添加匿名 struct{}, | ||
g.adjList[vet1][vet2] = struct{}{} | ||
g.adjList[vet2][vet1] = struct{}{} | ||
} | ||
|
||
/* 删除边 */ | ||
func (g *graphAdjList) removeEdge(vet1 vertex, vet2 vertex) { | ||
_, ok1 := g.adjList[vet1] | ||
_, ok2 := g.adjList[vet2] | ||
if !ok1 || !ok2 || vet1 == vet2 { | ||
panic("error") | ||
} | ||
// 删除边 vet1 - vet2, 借助 delete 来删除 map 中的键 | ||
delete(g.adjList[vet1], vet2) | ||
delete(g.adjList[vet2], vet1) | ||
} | ||
|
||
/* 添加顶点 */ | ||
func (g *graphAdjList) addVertex(vet vertex) { | ||
_, ok := g.adjList[vet] | ||
if ok { | ||
return | ||
} | ||
// 在邻接表中添加一个新链表(即 set) | ||
g.adjList[vet] = make(map[vertex]struct{}) | ||
} | ||
|
||
/* 删除顶点 */ | ||
func (g *graphAdjList) removeVertex(vet vertex) { | ||
_, ok := g.adjList[vet] | ||
if !ok { | ||
panic("error") | ||
} | ||
// 在邻接表中删除顶点 vet 对应的链表 | ||
delete(g.adjList, vet) | ||
// 遍历其它顶点的链表(即 Set),删除所有包含 vet 的边 | ||
for _, set := range g.adjList { | ||
// 操作 | ||
delete(set, vet) | ||
} | ||
} | ||
|
||
/* 打印邻接表 */ | ||
func (g *graphAdjList) print() { | ||
var builder strings.Builder | ||
fmt.Printf("邻接表 = \n") | ||
for k, v := range g.adjList { | ||
builder.WriteString("\t\t" + strconv.Itoa(k.val) + ": ") | ||
for vet := range v { | ||
builder.WriteString(strconv.Itoa(vet.val) + " ") | ||
} | ||
fmt.Println(builder.String()) | ||
builder.Reset() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// File: graph_adjacency_list_test.go | ||
// Created Time: 2023-01-31 | ||
// Author: Reanon ([email protected]) | ||
|
||
package chapter_graph | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
func TestGraphAdjList(t *testing.T) { | ||
/* 初始化无向图 */ | ||
v0 := newVertex(1) | ||
v1 := newVertex(3) | ||
v2 := newVertex(2) | ||
v3 := newVertex(5) | ||
v4 := newVertex(4) | ||
edges := [][]vertex{{v0, v1}, {v1, v2}, {v2, v3}, {v0, v3}, {v2, v4}, {v3, v4}} | ||
graph := newGraphAdjList(edges) | ||
fmt.Println("初始化后,图为:") | ||
graph.print() | ||
|
||
/* 添加边 */ | ||
// 顶点 1, 2 即 v0, v2 | ||
graph.addEdge(v0, v2) | ||
fmt.Println("\n添加边 1-2 后,图为") | ||
graph.print() | ||
|
||
/* 删除边 */ | ||
// 顶点 1, 3 即 v0, v1 | ||
graph.removeEdge(v0, v1) | ||
fmt.Println("\n删除边 1-3 后,图为") | ||
graph.print() | ||
|
||
/* 添加顶点 */ | ||
v5 := newVertex(6) | ||
graph.addVertex(v5) | ||
fmt.Println("\n添加顶点 6 后,图为") | ||
graph.print() | ||
|
||
/* 删除顶点 */ | ||
// 顶点 3 即 v1 | ||
graph.removeVertex(v1) | ||
fmt.Println("\n删除顶点 3 后,图为") | ||
graph.print() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// File: graph_adjacency_matrix.go | ||
// Created Time: 2023-01-31 | ||
// Author: Reanon ([email protected]) | ||
|
||
package chapter_graph | ||
|
||
import "fmt" | ||
|
||
/* 基于邻接矩阵实现的无向图类 */ | ||
type graphAdjMat struct { | ||
// 顶点列表,元素代表“顶点值”,索引代表“顶点索引” | ||
vertices []int | ||
// 邻接矩阵,行列索引对应“顶点索引” | ||
adjMat [][]int | ||
} | ||
|
||
func newGraphAdjMat(vertices []int, edges [][]int) *graphAdjMat { | ||
// 添加顶点 | ||
n := len(vertices) | ||
adjMat := make([][]int, n) | ||
for i := range adjMat { | ||
adjMat[i] = make([]int, n) | ||
} | ||
// 初始化图 | ||
g := &graphAdjMat{ | ||
vertices: vertices, | ||
adjMat: adjMat, | ||
} | ||
// 添加边 | ||
// 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 | ||
for i := range edges { | ||
g.addEdge(edges[i][0], edges[i][1]) | ||
} | ||
return g | ||
} | ||
|
||
/* 获取顶点数量 */ | ||
func (g *graphAdjMat) size() int { | ||
return len(g.vertices) | ||
} | ||
|
||
/* 添加顶点 */ | ||
func (g *graphAdjMat) addVertex(val int) { | ||
n := g.size() | ||
// 向顶点列表中添加新顶点的值 | ||
g.vertices = append(g.vertices, val) | ||
// 在邻接矩阵中添加一行 | ||
newRow := make([]int, n) | ||
g.adjMat = append(g.adjMat, newRow) | ||
// 在邻接矩阵中添加一列 | ||
for i := range g.adjMat { | ||
g.adjMat[i] = append(g.adjMat[i], 0) | ||
} | ||
} | ||
|
||
/* 删除顶点 */ | ||
func (g *graphAdjMat) removeVertex(index int) { | ||
if index >= g.size() { | ||
return | ||
} | ||
// 在顶点列表中移除索引 index 的顶点 | ||
g.vertices = append(g.vertices[:index], g.vertices[index+1:]...) | ||
// 在邻接矩阵中删除索引 index 的行 | ||
g.adjMat = append(g.adjMat[:index], g.adjMat[index+1:]...) | ||
// 在邻接矩阵中删除索引 index 的列 | ||
for i := range g.adjMat { | ||
g.adjMat[i] = append(g.adjMat[i][:index], g.adjMat[i][index+1:]...) | ||
} | ||
} | ||
|
||
/* 添加边 */ | ||
// 参数 i, j 对应 vertices 元素索引 | ||
func (g *graphAdjMat) addEdge(i, j int) { | ||
// 索引越界与相等处理 | ||
if i < 0 || j < 0 || i >= g.size() || j >= g.size() || i == j { | ||
fmt.Errorf("%s", "Index Out Of Bounds Exception") | ||
} | ||
// 在无向图中,邻接矩阵沿主对角线对称,即满足 (i, j) == (j, i) | ||
g.adjMat[i][j] = 1 | ||
g.adjMat[j][i] = 1 | ||
} | ||
|
||
/* 删除边 */ | ||
// 参数 i, j 对应 vertices 元素索引 | ||
func (g *graphAdjMat) removeEdge(i, j int) { | ||
// 索引越界与相等处理 | ||
if i < 0 || j < 0 || i >= g.size() || j >= g.size() || i == j { | ||
fmt.Errorf("%s", "Index Out Of Bounds Exception") | ||
} | ||
g.adjMat[i][j] = 0 | ||
g.adjMat[j][i] = 0 | ||
} | ||
|
||
/* 打印邻接矩阵 */ | ||
func (g *graphAdjMat) print() { | ||
fmt.Printf("\t顶点列表 = %v\n", g.vertices) | ||
fmt.Printf("\t邻接矩阵 = \n") | ||
for i := range g.adjMat { | ||
fmt.Printf("\t\t\t%v\n", g.adjMat[i]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// File: graph_adjacency_matrix_test.go | ||
// Created Time: 2023-01-31 | ||
// Author: Reanon ([email protected]) | ||
|
||
package chapter_graph | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
func TestGraphAdjMat(t *testing.T) { | ||
/* 初始化无向图 */ | ||
// 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 | ||
vertices := []int{1, 3, 2, 5, 4} | ||
edges := [][]int{{0, 1}, {0, 2}, {1, 2}, {2, 3}, {0, 3}, {2, 4}, {3, 4}} | ||
graph := newGraphAdjMat(vertices, edges) | ||
fmt.Println("初始化后,图为:") | ||
graph.print() | ||
|
||
/* 添加边 */ | ||
// 顶点 1, 2 的索引分别为 0, 2 | ||
graph.addEdge(0, 2) | ||
fmt.Println("添加边 1-2 后,图为") | ||
graph.print() | ||
|
||
/* 删除边 */ | ||
// 顶点 1, 3 的索引分别为 0, 1 | ||
graph.removeEdge(0, 1) | ||
fmt.Println("删除边 1-3 后,图为") | ||
graph.print() | ||
|
||
/* 添加顶点 */ | ||
graph.addVertex(6) | ||
fmt.Println("添加顶点 6 后,图为") | ||
graph.print() | ||
|
||
/* 删除顶点 */ | ||
// 顶点 3 的索引为 1 | ||
graph.removeVertex(1) | ||
fmt.Println("删除顶点 3 后,图为") | ||
graph.print() | ||
} |
Oops, something went wrong.