diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index 0b5a200ed..206578d22 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -229,5 +229,25 @@ path = "chapter_backtracking/subset_sum_i.rs" name = "subset_sum_ii" path = "chapter_backtracking/subset_sum_ii.rs" +# Run Command: cargo run --bin graph_adjacency_list +[[bin]] +name = "graph_adjacency_list" +path = "chapter_graph/graph_adjacency_list.rs" + +# Run Command: cargo run --bin graph_adjacency_matrix +[[bin]] +name = "graph_adjacency_matrix" +path = "chapter_graph/graph_adjacency_matrix.rs" + +# Run Command: cargo run --bin graph_bfs +[[bin]] +name = "graph_bfs" +path = "chapter_graph/graph_bfs.rs" + +# Run Command: cargo run --bin graph_dfs +[[bin]] +name = "graph_dfs" +path = "chapter_graph/graph_dfs.rs" + [dependencies] rand = "0.8.5" diff --git a/codes/rust/chapter_graph/graph_adjacency_list.rs b/codes/rust/chapter_graph/graph_adjacency_list.rs new file mode 100644 index 000000000..42b98d34b --- /dev/null +++ b/codes/rust/chapter_graph/graph_adjacency_list.rs @@ -0,0 +1,142 @@ +/* + * File: graph_adjacency_list.rs + * Created Time: 2023-07-12 + * Author: night-cruise (2586447362@qq.com) + */ + +include!("../include/vertex.rs"); + +use std::collections::HashMap; + +/* 基于邻接表实现的无向图类型 */ +pub struct GraphAdjList { + // 邻接表,key: 顶点,value:该顶点的所有邻接顶点 + pub adj_list: HashMap>, +} + +impl GraphAdjList { + /* 构造方法 */ + pub fn new(edges: Vec<[Vertex; 2]>) -> Self { + let mut graph = GraphAdjList { + adj_list: HashMap::new(), + }; + // 添加所有顶点和边 + for edge in edges { + graph.add_vertex(edge[0]); + graph.add_vertex(edge[1]); + graph.add_edge(edge[0], edge[1]); + } + + graph + } + + /* 获取顶点数量 */ + #[allow(unused)] + pub fn size(&self) -> usize { + self.adj_list.len() + } + + /* 添加边 */ + pub fn add_edge(&mut self, vet1: Vertex, vet2: Vertex) { + if !self.adj_list.contains_key(&vet1) || !self.adj_list.contains_key(&vet2) || vet1 == vet2 + { + panic!("value error"); + } + // 添加边 vet1 - vet2 + self.adj_list.get_mut(&vet1).unwrap().push(vet2); + self.adj_list.get_mut(&vet2).unwrap().push(vet1); + } + + /* 删除边 */ + #[allow(unused)] + pub fn remove_edge(&mut self, vet1: Vertex, vet2: Vertex) { + if !self.adj_list.contains_key(&vet1) || !self.adj_list.contains_key(&vet2) || vet1 == vet2 + { + panic!("value error"); + } + // 删除边 vet1 - vet2 + self.adj_list + .get_mut(&vet1) + .unwrap() + .retain(|&vet| vet != vet2); + self.adj_list + .get_mut(&vet2) + .unwrap() + .retain(|&vet| vet != vet1); + } + + /* 添加顶点 */ + pub fn add_vertex(&mut self, vet: Vertex) { + if self.adj_list.contains_key(&vet) { + return; + } + // 在邻接表中添加一个新链表 + self.adj_list.insert(vet, vec![]); + } + + /* 删除顶点 */ + #[allow(unused)] + pub fn remove_vertex(&mut self, vet: Vertex) { + if !self.adj_list.contains_key(&vet) { + panic!("value error"); + } + // 在邻接表中删除顶点 vet 对应的链表 + self.adj_list.remove(&vet); + // 遍历其他顶点的链表,删除所有包含 vet 的边 + for list in self.adj_list.values_mut() { + list.retain(|&v| v != vet); + } + } + + /* 打印邻接表 */ + pub fn print(&self) { + println!("邻接表 ="); + for (vertex, list) in &self.adj_list { + let list = list.iter().map(|vertex| vertex.val).collect::>(); + println!("{}: {:?},", vertex.val, list); + } + } +} + +/* Driver Code */ +#[allow(unused)] +fn main() { + /* 初始化无向图 */ + let v = vals_to_vets(vec![1, 3, 2, 5, 4]); + let edges = vec![ + [v[0], v[1]], + [v[0], v[3]], + [v[1], v[2]], + [v[2], v[3]], + [v[2], v[4]], + [v[3], v[4]], + ]; + + let mut graph = GraphAdjList::new(edges); + println!("\n初始化后,图为"); + graph.print(); + + /* 添加边 */ + // 顶点 1, 2 即 v[0], v[2] + graph.add_edge(v[0], v[2]); + println!("\n添加边 1-2 后,图为"); + graph.print(); + + /* 删除边 */ + // 顶点 1, 3 即 v[0], v[1] + graph.remove_edge(v[0], v[1]); + println!("\n删除边 1-3 后,图为"); + graph.print(); + + /* 添加顶点 */ + let v5 = Vertex { val: 6 }; + graph.add_vertex(v5); + println!("\n添加顶点 6 后,图为"); + graph.print(); + + /* 删除顶点 */ + // 顶点 3 即 v[1] + graph.remove_vertex(v[1]); + println!("\n删除顶点 3 后,图为"); + graph.print(); +} \ No newline at end of file diff --git a/codes/rust/chapter_graph/graph_adjacency_matrix.rs b/codes/rust/chapter_graph/graph_adjacency_matrix.rs new file mode 100644 index 000000000..a94e20a5b --- /dev/null +++ b/codes/rust/chapter_graph/graph_adjacency_matrix.rs @@ -0,0 +1,136 @@ +/* + * File: graph_adjacency_matrix.rs + * Created Time: 2023-07-12 + * Author: night-cruise (2586447362@qq.com) + */ + +/* 基于邻接矩阵实现的无向图类型 */ +pub struct GraphAdjMat { + // 顶点列表,元素代表“顶点值”,索引代表“顶点索引” + pub vertices: Vec, + // 邻接矩阵,行列索引对应“顶点索引” + pub adj_mat: Vec>, +} + +impl GraphAdjMat { + /* 构造方法 */ + pub fn new(vertices: Vec, edges: Vec<[usize; 2]>) -> Self { + let mut graph = GraphAdjMat { + vertices: vec![], + adj_mat: vec![], + }; + // 添加顶点 + for val in vertices { + graph.add_vertex(val); + } + // 添加边 + // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 + for edge in edges { + graph.add_edge(edge[0], edge[1]) + } + + graph + } + + /* 获取顶点数量 */ + pub fn size(&self) -> usize { + self.vertices.len() + } + + /* 添加顶点 */ + pub fn add_vertex(&mut self, val: i32) { + let n = self.size(); + // 向顶点列表中添加新顶点的值 + self.vertices.push(val); + // 在邻接矩阵中添加一行 + self.adj_mat.push(vec![0; n]); + // 在邻接矩阵中添加一列 + for row in &mut self.adj_mat { + row.push(0); + } + } + + /* 删除顶点 */ + pub fn remove_vertex(&mut self, index: usize) { + if index >= self.size() { + panic!("index error") + } + // 在顶点列表中移除索引 index 的顶点 + self.vertices.remove(index); + // 在邻接矩阵中删除索引 index 的行 + self.adj_mat.remove(index); + // 在邻接矩阵中删除索引 index 的列 + for row in &mut self.adj_mat { + row.remove(index); + } + } + + /* 添加边 */ + pub fn add_edge(&mut self, i: usize, j: usize) { + // 参数 i, j 对应 vertices 元素索引 + // 索引越界与相等处理 + if i >= self.size() || j >= self.size() || i == j { + panic!("index error") + } + // 在无向图中,邻接矩阵沿主对角线对称,即满足 (i, j) == (j, i) + self.adj_mat[i][j] = 1; + self.adj_mat[j][i] = 1; + } + + /* 删除边 */ + // 参数 i, j 对应 vertices 元素索引 + pub fn remove_edge(&mut self, i: usize, j: usize) { + // 参数 i, j 对应 vertices 元素索引 + // 索引越界与相等处理 + if i >= self.size() || j >= self.size() || i == j { + panic!("index error") + } + self.adj_mat[i][j] = 0; + self.adj_mat[j][i] = 0; + } + + /* 打印邻接矩阵 */ + pub fn print(&self) { + println!("顶点列表 = {:?}", self.vertices); + println!("邻接矩阵 ="); + println!("["); + for row in &self.adj_mat { + println!(" {:?},", row); + } + println!("]") + } +} + +/* Driver Code */ +fn main() { + /* 初始化无向图 */ + // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 + let vertices = vec![1, 3, 2, 5, 4]; + let edges = vec![[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]]; + let mut graph = GraphAdjMat::new(vertices, edges); + println!("\n初始化后,图为"); + graph.print(); + + /* 添加边 */ + // 顶点 1, 2 的索引分别为 0, 2 + graph.add_edge(0, 2); + println!("\n添加边 1-2 后,图为"); + graph.print(); + + /* 删除边 */ + // 顶点 1, 3 的索引分别为 0, 1 + graph.remove_edge(0, 1); + println!("\n删除边 1-3 后,图为"); + graph.print(); + + /* 添加顶点 */ + graph.add_vertex(6); + println!("\n添加顶点 6 后,图为"); + graph.print(); + + /* 删除顶点 */ + // 顶点 3 的索引为 1 + graph.remove_vertex(1); + println!("\n删除顶点 3 后,图为"); + graph.print(); +} \ No newline at end of file diff --git a/codes/rust/chapter_graph/graph_bfs.rs b/codes/rust/chapter_graph/graph_bfs.rs new file mode 100644 index 000000000..32eb59eec --- /dev/null +++ b/codes/rust/chapter_graph/graph_bfs.rs @@ -0,0 +1,69 @@ +/* + * File: graph_bfs.rs + * Created Time: 2023-07-12 + * Author: night-cruise (2586447362@qq.com) + */ + +mod graph_adjacency_list; + +use std::collections::{HashSet, VecDeque}; +use graph_adjacency_list::GraphAdjList; +use graph_adjacency_list::{Vertex, vets_to_vals, vals_to_vets}; + +/* 广度优先遍历 BFS */ +// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点 +fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { + // 顶点遍历序列 + let mut res = vec![]; + // 哈希表,用于记录已被访问过的顶点 + let mut visited = HashSet::new(); + visited.insert(start_vet); + // 队列用于实现 BFS + let mut que = VecDeque::new(); + que.push_back(start_vet); + // 以顶点 vet 为起点,循环直至访问完所有顶点 + while !que.is_empty() { + let vet = que.pop_front().unwrap(); // 队首顶点出队 + res.push(vet); // 记录访问顶点 + // 遍历该顶点的所有邻接顶点 + if let Some(adj_vets) = graph.adj_list.get(&vet) { + for &adj_vet in adj_vets { + if visited.contains(&adj_vet) { + continue; // 跳过已被访问过的顶点 + } + que.push_back(adj_vet); // 只入队未访问的顶点 + visited.insert(adj_vet); // 标记该顶点已被访问 + } + } + } + // 返回顶点遍历序列 + res +} + +/* Driver Code */ +fn main() { + /* 初始化无向图 */ + let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + let edges = vec![ + [v[0], v[1]], + [v[0], v[3]], + [v[1], v[2]], + [v[1], v[4]], + [v[2], v[5]], + [v[3], v[4]], + [v[3], v[6]], + [v[4], v[5]], + [v[4], v[7]], + [v[5], v[8]], + [v[6], v[7]], + [v[7], v[8]], + ]; + let graph = GraphAdjList::new(edges); + println!("\n初始化后,图为"); + graph.print(); + + /* 广度优先遍历 BFS */ + let res = graph_bfs(graph, v[0]); + println!("\n广度优先遍历(BFS)顶点序列为"); + println!("{:?}", vets_to_vals(res)); +} \ No newline at end of file diff --git a/codes/rust/chapter_graph/graph_dfs.rs b/codes/rust/chapter_graph/graph_dfs.rs new file mode 100644 index 000000000..dc339e34c --- /dev/null +++ b/codes/rust/chapter_graph/graph_dfs.rs @@ -0,0 +1,61 @@ +/* + * File: graph_dfs.rs + * Created Time: 2023-07-12 + * Author: night-cruise (2586447362@qq.com) + */ + +mod graph_adjacency_list; + +use std::collections::HashSet; +use graph_adjacency_list::GraphAdjList; +use graph_adjacency_list::{Vertex, vets_to_vals, vals_to_vets}; + +/* 深度优先遍历 DFS 辅助函数 */ +fn dfs(graph: &GraphAdjList, visited: &mut HashSet, res: &mut Vec, vet: Vertex) { + res.push(vet); // 记录访问顶点 + visited.insert(vet); // 标记该顶点已被访问 + // 遍历该顶点的所有邻接顶点 + if let Some(adj_vets) = graph.adj_list.get(&vet) { + for &adj_vet in adj_vets { + if visited.contains(&adj_vet) { + continue; // 跳过已被访问过的顶点 + } + // 递归访问邻接顶点 + dfs(graph, visited, res, adj_vet); + } + } +} + +/* 深度优先遍历 DFS */ +// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点 +fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { + // 顶点遍历序列 + let mut res = vec![]; + // 哈希表,用于记录已被访问过的顶点 + let mut visited = HashSet::new(); + dfs(&graph, &mut visited, &mut res, start_vet); + + res +} + +/* Driver Code */ +fn main() { + /* 初始化无向图 */ + let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6]); + let edges = vec![ + [v[0], v[1]], + [v[0], v[3]], + [v[1], v[2]], + [v[2], v[5]], + [v[4], v[5]], + [v[5], v[6]], + ]; + let graph = GraphAdjList::new(edges); + println!("\n初始化后,图为"); + graph.print(); + + /* 深度优先遍历 DFS */ + let res = graph_dfs(graph, v[0]); + println!("\n深度优先遍历(DFS)顶点序列为"); + println!("{:?}", vets_to_vals(res)); +} \ No newline at end of file diff --git a/codes/rust/include/include.rs b/codes/rust/include/include.rs index f227e3d4a..22841582d 100644 --- a/codes/rust/include/include.rs +++ b/codes/rust/include/include.rs @@ -6,4 +6,5 @@ pub mod print_util; pub mod list_node; -pub mod tree_node; \ No newline at end of file +pub mod tree_node; +pub mod vertex; \ No newline at end of file diff --git a/codes/rust/include/vertex.rs b/codes/rust/include/vertex.rs new file mode 100644 index 000000000..5aa3a6b5e --- /dev/null +++ b/codes/rust/include/vertex.rs @@ -0,0 +1,21 @@ +/* + * File: vertex.rs + * Created Time: 2023-07-13 + * Author: night-cruise (2586447362@qq.com) + */ + +/* 顶点类型 */ +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct Vertex { + pub val: i32 +} + +/* 输入值列表 vals ,返回顶点列表 vets */ +pub fn vals_to_vets(vals: Vec) -> Vec { + vals.into_iter().map(|val| Vertex { val }).collect() +} + +/* 输入顶点列表 vets ,返回值列表 vals */ +pub fn vets_to_vals(vets: Vec) -> Vec { + vets.into_iter().map(|vet| vet.val).collect() +} \ No newline at end of file