This commit is contained in:
krahets 2024-04-26 19:21:07 +08:00
parent b3c757c9f4
commit f986ae3c8c
5 changed files with 372 additions and 12 deletions

View file

@ -1130,7 +1130,80 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="graph_adjacency_matrix.rb" ```ruby title="graph_adjacency_matrix.rb"
[class]{GraphAdjMat}-[func]{} ### 基于邻接矩阵实现的无向图类 ###
class GraphAdjMat
def initialize(vertices, edges)
### 构造方法 ###
# 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
@vertices = []
# 邻接矩阵,行列索引对应“顶点索引”
@adj_mat = []
# 添加顶点
vertices.each { |val| add_vertex(val) }
# 添加边
# 请注意edges 元素代表顶点索引,即对应 vertices 元素索引
edges.each { |e| add_edge(e[0], e[1]) }
end
### 获取顶点数量 ###
def size
@vertices.length
end
### 添加顶点 ###
def add_vertex(val)
n = size
# 向顶点列表中添加新顶点的值
@vertices << val
# 在邻接矩阵中添加一行
new_row = Array.new(n, 0)
@adj_mat << new_row
# 在邻接矩阵中添加一列
@adj_mat.each { |row| row << 0 }
end
### 删除顶点 ###
def remove_vertex(index)
raise IndexError if index >= size
# 在顶点列表中移除索引 index 的顶点
@vertices.delete_at(index)
# 在邻接矩阵中删除索引 index 的行
@adj_mat.delete_at(index)
# 在邻接矩阵中删除索引 index 的列
@adj_mat.each { |row| row.delete_at(index) }
end
### 添加边 ###
def add_edge(i, j)
# 参数 i, j 对应 vertices 元素索引
# 索引越界与相等处理
if i < 0 || j < 0 || i >= size || j >= size || i == j
raise IndexError
end
# 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i)
@adj_mat[i][j] = 1
@adj_mat[j][i] = 1
end
### 删除边 ###
def remove_edge(i, j)
# 参数 i, j 对应 vertices 元素索引
# 索引越界与相等处理
if i < 0 || j < 0 || i >= size || j >= size || i == j
raise IndexError
end
@adj_mat[i][j] = 0
@adj_mat[j][i] = 0
end
### 打印邻接矩阵 ###
def __print__
puts "顶点列表 = #{@vertices}"
puts '邻接矩阵 ='
print_matrix(@adj_mat)
end
end
``` ```
=== "Zig" === "Zig"
@ -2233,7 +2306,73 @@ comments: true
=== "Ruby" === "Ruby"
```ruby title="graph_adjacency_list.rb" ```ruby title="graph_adjacency_list.rb"
[class]{GraphAdjList}-[func]{} ### 基于邻接表实现的无向图类 ###
class GraphAdjList
attr_reader :adj_list
### 构造方法 ###
def initialize(edges)
# 邻接表key顶点value该顶点的所有邻接顶点
@adj_list = {}
# 添加所有顶点和边
for edge in edges
add_vertex(edge[0])
add_vertex(edge[1])
add_edge(edge[0], edge[1])
end
end
### 获取顶点数量 ###
def size
@adj_list.length
end
### 添加边 ###
def add_edge(vet1, vet2)
raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2)
@adj_list[vet1] << vet2
@adj_list[vet2] << vet1
end
### 删除边 ###
def remove_edge(vet1, vet2)
raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2)
# 删除边 vet1 - vet2
@adj_list[vet1].delete(vet2)
@adj_list[vet2].delete(vet1)
end
### 添加顶点 ###
def add_vertex(vet)
return if @adj_list.include?(vet)
# 在邻接表中添加一个新链表
@adj_list[vet] = []
end
### 删除顶点 ###
def remove_vertex(vet)
raise ArgumentError unless @adj_list.include?(vet)
# 在邻接表中删除顶点 vet 对应的链表
@adj_list.delete(vet)
# 遍历其他顶点的链表,删除所有包含 vet 的边
for vertex in @adj_list
@adj_list[vertex.first].delete(vet) if @adj_list[vertex.first].include?(vet)
end
end
### 打印邻接表 ###
def __print__
puts '邻接表 ='
for vertex in @adj_list
tmp = @adj_list[vertex.first].map { |v| v.val }
puts "#{vertex.first.val}: #{tmp},"
end
end
end
``` ```
=== "Zig" === "Zig"

View file

@ -447,7 +447,29 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
=== "Ruby" === "Ruby"
```ruby title="graph_bfs.rb" ```ruby title="graph_bfs.rb"
[class]{}-[func]{graph_bfs} ### 广度优先遍历 ###
def graph_bfs(graph, start_vet)
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
# 顶点遍历序列
res = []
# 哈希表,用于记录已被访问过的顶点
visited = Set.new([start_vet])
# 队列用于实现 BFS
que = [start_vet]
# 以顶点 vet 为起点,循环直至访问完所有顶点
while que.length > 0
vet = que.shift # 队首顶点出队
res << vet # 记录访问顶点
# 遍历该顶点的所有邻接顶点
for adj_vet in graph.adj_list[vet]
next if visited.include?(adj_vet) # 跳过已被访问的顶点
que << adj_vet # 只入队未访问的顶点
visited.add(adj_vet) # 标记该顶点已被访问
end
end
# 返回顶点遍历序列
res
end
``` ```
=== "Zig" === "Zig"
@ -892,9 +914,28 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
=== "Ruby" === "Ruby"
```ruby title="graph_dfs.rb" ```ruby title="graph_dfs.rb"
[class]{}-[func]{dfs} ### 深度优先遍历辅助函数 ###
def dfs(graph, visited, res, vet)
res << vet # 记录访问顶点
visited.add(vet) # 标记该顶点已被访问
# 遍历该顶点的所有邻接顶点
for adj_vet in graph.adj_list[vet]
next if visited.include?(adj_vet) # 跳过已被访问的顶点
# 递归访问邻接顶点
dfs(graph, visited, res, adj_vet)
end
end
[class]{}-[func]{graph_dfs} ### 深度优先遍历 ###
def graph_dfs(graph, start_vet)
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
# 顶点遍历序列
res = []
# 哈希表,用于记录已被访问过的顶点
visited = Set.new
dfs(graph, visited, res, start_vet)
res
end
``` ```
=== "Zig" === "Zig"

View file

@ -1130,7 +1130,80 @@ Below is the implementation code for graphs represented using an adjacency matri
=== "Ruby" === "Ruby"
```ruby title="graph_adjacency_matrix.rb" ```ruby title="graph_adjacency_matrix.rb"
[class]{GraphAdjMat}-[func]{} ### 基于邻接矩阵实现的无向图类 ###
class GraphAdjMat
def initialize(vertices, edges)
### 构造方法 ###
# 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
@vertices = []
# 邻接矩阵,行列索引对应“顶点索引”
@adj_mat = []
# 添加顶点
vertices.each { |val| add_vertex(val) }
# 添加边
# 请注意edges 元素代表顶点索引,即对应 vertices 元素索引
edges.each { |e| add_edge(e[0], e[1]) }
end
### 获取顶点数量 ###
def size
@vertices.length
end
### 添加顶点 ###
def add_vertex(val)
n = size
# 向顶点列表中添加新顶点的值
@vertices << val
# 在邻接矩阵中添加一行
new_row = Array.new(n, 0)
@adj_mat << new_row
# 在邻接矩阵中添加一列
@adj_mat.each { |row| row << 0 }
end
### 删除顶点 ###
def remove_vertex(index)
raise IndexError if index >= size
# 在顶点列表中移除索引 index 的顶点
@vertices.delete_at(index)
# 在邻接矩阵中删除索引 index 的行
@adj_mat.delete_at(index)
# 在邻接矩阵中删除索引 index 的列
@adj_mat.each { |row| row.delete_at(index) }
end
### 添加边 ###
def add_edge(i, j)
# 参数 i, j 对应 vertices 元素索引
# 索引越界与相等处理
if i < 0 || j < 0 || i >= size || j >= size || i == j
raise IndexError
end
# 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i)
@adj_mat[i][j] = 1
@adj_mat[j][i] = 1
end
### 删除边 ###
def remove_edge(i, j)
# 参数 i, j 对应 vertices 元素索引
# 索引越界与相等处理
if i < 0 || j < 0 || i >= size || j >= size || i == j
raise IndexError
end
@adj_mat[i][j] = 0
@adj_mat[j][i] = 0
end
### 打印邻接矩阵 ###
def __print__
puts "顶点列表 = #{@vertices}"
puts '邻接矩阵 ='
print_matrix(@adj_mat)
end
end
``` ```
=== "Zig" === "Zig"
@ -2233,7 +2306,73 @@ Additionally, we use the `Vertex` class to represent vertices in the adjacency l
=== "Ruby" === "Ruby"
```ruby title="graph_adjacency_list.rb" ```ruby title="graph_adjacency_list.rb"
[class]{GraphAdjList}-[func]{} ### 基于邻接表实现的无向图类 ###
class GraphAdjList
attr_reader :adj_list
### 构造方法 ###
def initialize(edges)
# 邻接表key顶点value该顶点的所有邻接顶点
@adj_list = {}
# 添加所有顶点和边
for edge in edges
add_vertex(edge[0])
add_vertex(edge[1])
add_edge(edge[0], edge[1])
end
end
### 获取顶点数量 ###
def size
@adj_list.length
end
### 添加边 ###
def add_edge(vet1, vet2)
raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2)
@adj_list[vet1] << vet2
@adj_list[vet2] << vet1
end
### 删除边 ###
def remove_edge(vet1, vet2)
raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2)
# 删除边 vet1 - vet2
@adj_list[vet1].delete(vet2)
@adj_list[vet2].delete(vet1)
end
### 添加顶点 ###
def add_vertex(vet)
return if @adj_list.include?(vet)
# 在邻接表中添加一个新链表
@adj_list[vet] = []
end
### 删除顶点 ###
def remove_vertex(vet)
raise ArgumentError unless @adj_list.include?(vet)
# 在邻接表中删除顶点 vet 对应的链表
@adj_list.delete(vet)
# 遍历其他顶点的链表,删除所有包含 vet 的边
for vertex in @adj_list
@adj_list[vertex.first].delete(vet) if @adj_list[vertex.first].include?(vet)
end
end
### 打印邻接表 ###
def __print__
puts '邻接表 ='
for vertex in @adj_list
tmp = @adj_list[vertex.first].map { |v| v.val }
puts "#{vertex.first.val}: #{tmp},"
end
end
end
``` ```
=== "Zig" === "Zig"

View file

@ -447,7 +447,29 @@ To prevent revisiting vertices, we use a hash table `visited` to record which no
=== "Ruby" === "Ruby"
```ruby title="graph_bfs.rb" ```ruby title="graph_bfs.rb"
[class]{}-[func]{graph_bfs} ### 广度优先遍历 ###
def graph_bfs(graph, start_vet)
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
# 顶点遍历序列
res = []
# 哈希表,用于记录已被访问过的顶点
visited = Set.new([start_vet])
# 队列用于实现 BFS
que = [start_vet]
# 以顶点 vet 为起点,循环直至访问完所有顶点
while que.length > 0
vet = que.shift # 队首顶点出队
res << vet # 记录访问顶点
# 遍历该顶点的所有邻接顶点
for adj_vet in graph.adj_list[vet]
next if visited.include?(adj_vet) # 跳过已被访问的顶点
que << adj_vet # 只入队未访问的顶点
visited.add(adj_vet) # 标记该顶点已被访问
end
end
# 返回顶点遍历序列
res
end
``` ```
=== "Zig" === "Zig"
@ -892,9 +914,28 @@ This "go as far as possible and then return" algorithm paradigm is usually imple
=== "Ruby" === "Ruby"
```ruby title="graph_dfs.rb" ```ruby title="graph_dfs.rb"
[class]{}-[func]{dfs} ### 深度优先遍历辅助函数 ###
def dfs(graph, visited, res, vet)
res << vet # 记录访问顶点
visited.add(vet) # 标记该顶点已被访问
# 遍历该顶点的所有邻接顶点
for adj_vet in graph.adj_list[vet]
next if visited.include?(adj_vet) # 跳过已被访问的顶点
# 递归访问邻接顶点
dfs(graph, visited, res, adj_vet)
end
end
[class]{}-[func]{graph_dfs} ### 深度优先遍历 ###
def graph_dfs(graph, start_vet)
# 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
# 顶点遍历序列
res = []
# 哈希表,用于记录已被访问过的顶点
visited = Set.new
dfs(graph, visited, res, start_vet)
res
end
``` ```
=== "Zig" === "Zig"

View file

@ -9,9 +9,9 @@ icon: material/graph-outline
!!! abstract !!! abstract
The towering tree, full of vitality with its roots deep and leaves lush, branches spreading wide. The towering tree, vibrant with it's deep roots and lush leaves, branches spreading wide.
It vividly demonstrates the form of data divide-and-conquer. It vividly illustrates the concept of divide-and-conquer in data.
## Chapter contents ## Chapter contents