oxihuman_core/
graph_search.rs1#![allow(dead_code)]
4
5use std::collections::{HashSet, VecDeque};
8
9pub struct AdjGraph {
11 adj: Vec<Vec<usize>>,
12}
13
14pub fn new_adj_graph(n: usize) -> AdjGraph {
16 AdjGraph {
17 adj: vec![Vec::new(); n],
18 }
19}
20
21impl AdjGraph {
22 pub fn add_edge(&mut self, u: usize, v: usize) {
24 if u < self.adj.len() {
25 self.adj[u].push(v);
26 }
27 }
28
29 pub fn add_undirected(&mut self, u: usize, v: usize) {
31 self.add_edge(u, v);
32 self.add_edge(v, u);
33 }
34
35 pub fn vertex_count(&self) -> usize {
37 self.adj.len()
38 }
39
40 pub fn edge_count(&self) -> usize {
42 self.adj.iter().map(|v| v.len()).sum()
43 }
44
45 pub fn bfs(&self, start: usize) -> Vec<usize> {
47 let n = self.adj.len();
48 if start >= n {
49 return Vec::new();
50 }
51 let mut visited = vec![false; n];
52 let mut order = Vec::new();
53 let mut queue = VecDeque::new();
54 visited[start] = true;
55 queue.push_back(start);
56 while let Some(u) = queue.pop_front() {
57 order.push(u);
58 for &v in &self.adj[u] {
59 if v < n && !visited[v] {
60 visited[v] = true;
61 queue.push_back(v);
62 }
63 }
64 }
65 order
66 }
67
68 pub fn dfs(&self, start: usize) -> Vec<usize> {
70 let n = self.adj.len();
71 if start >= n {
72 return Vec::new();
73 }
74 let mut visited = vec![false; n];
75 let mut order = Vec::new();
76 self.dfs_rec(start, &mut visited, &mut order);
77 order
78 }
79
80 fn dfs_rec(&self, u: usize, visited: &mut Vec<bool>, order: &mut Vec<usize>) {
81 visited[u] = true;
82 order.push(u);
83 for &v in &self.adj[u] {
84 if v < self.adj.len() && !visited[v] {
85 self.dfs_rec(v, visited, order);
86 }
87 }
88 }
89
90 pub fn shortest_path(&self, src: usize, dst: usize) -> Option<Vec<usize>> {
92 let n = self.adj.len();
93 if src >= n || dst >= n {
94 return None;
95 }
96 let mut prev = vec![usize::MAX; n];
97 let mut visited = vec![false; n];
98 let mut queue = VecDeque::new();
99 visited[src] = true;
100 queue.push_back(src);
101 while let Some(u) = queue.pop_front() {
102 if u == dst {
103 let mut path = Vec::new();
104 let mut cur = dst;
105 while cur != src {
106 path.push(cur);
107 cur = prev[cur];
108 }
109 path.push(src);
110 path.reverse();
111 return Some(path);
112 }
113 for &v in &self.adj[u] {
114 if v < n && !visited[v] {
115 visited[v] = true;
116 prev[v] = u;
117 queue.push_back(v);
118 }
119 }
120 }
121 None
122 }
123
124 pub fn is_reachable(&self, src: usize, dst: usize) -> bool {
126 let visited: HashSet<usize> = self.bfs(src).into_iter().collect();
127 visited.contains(&dst)
128 }
129
130 pub fn bfs_levels(&self, start: usize) -> Vec<Option<usize>> {
132 let n = self.adj.len();
133 let mut levels = vec![None; n];
134 if start >= n {
135 return levels;
136 }
137 levels[start] = Some(0);
138 let mut queue = VecDeque::new();
139 queue.push_back(start);
140 while let Some(u) = queue.pop_front() {
141 let lvl = levels[u].unwrap_or(0);
142 for &v in &self.adj[u] {
143 if v < n && levels[v].is_none() {
144 levels[v] = Some(lvl + 1);
145 queue.push_back(v);
146 }
147 }
148 }
149 levels
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_new_graph() {
159 let g = new_adj_graph(5);
161 assert_eq!(g.vertex_count(), 5);
162 assert_eq!(g.edge_count(), 0);
163 }
164
165 #[test]
166 fn test_add_edge() {
167 let mut g = new_adj_graph(3);
169 g.add_edge(0, 1);
170 g.add_edge(1, 2);
171 assert_eq!(g.edge_count(), 2);
172 }
173
174 #[test]
175 fn test_bfs_order() {
176 let mut g = new_adj_graph(4);
178 g.add_undirected(0, 1);
179 g.add_undirected(0, 2);
180 g.add_undirected(1, 3);
181 let order = g.bfs(0);
182 assert_eq!(order[0], 0);
183 assert!(order.contains(&1));
184 assert!(order.contains(&3));
185 }
186
187 #[test]
188 fn test_dfs_visits_all() {
189 let mut g = new_adj_graph(5);
191 for i in 0..4 {
192 g.add_undirected(i, i + 1);
193 }
194 let order = g.dfs(0);
195 assert_eq!(order.len(), 5);
196 }
197
198 #[test]
199 fn test_shortest_path_found() {
200 let mut g = new_adj_graph(5);
202 g.add_undirected(0, 1);
203 g.add_undirected(1, 2);
204 g.add_undirected(2, 3);
205 let path = g.shortest_path(0, 3).expect("should succeed");
206 assert_eq!(path[0], 0);
207 assert_eq!(*path.last().expect("should succeed"), 3);
208 }
209
210 #[test]
211 fn test_shortest_path_none() {
212 let mut g = new_adj_graph(4);
214 g.add_edge(0, 1);
215 assert!(g.shortest_path(0, 3).is_none());
216 }
217
218 #[test]
219 fn test_is_reachable() {
220 let mut g = new_adj_graph(4);
222 g.add_undirected(0, 1);
223 g.add_undirected(1, 2);
224 assert!(g.is_reachable(0, 2));
225 assert!(!g.is_reachable(0, 3));
226 }
227
228 #[test]
229 fn test_bfs_levels() {
230 let mut g = new_adj_graph(5);
232 g.add_undirected(0, 1);
233 g.add_undirected(1, 2);
234 g.add_undirected(2, 3);
235 let levels = g.bfs_levels(0);
236 assert_eq!(levels[0], Some(0));
237 assert_eq!(levels[1], Some(1));
238 assert_eq!(levels[3], Some(3));
239 assert_eq!(levels[4], None);
240 }
241
242 #[test]
243 fn test_add_undirected() {
244 let mut g = new_adj_graph(2);
246 g.add_undirected(0, 1);
247 assert_eq!(g.edge_count(), 2);
248 }
249}