rust_igraph/algorithms/traversal/
bfs.rs1use std::collections::VecDeque;
9
10use crate::core::{Graph, IgraphResult, VertexId};
11
12pub fn bfs(graph: &Graph, root: VertexId) -> IgraphResult<Vec<VertexId>> {
34 graph.neighbors(root)?;
36
37 let n = graph.vcount();
38 let mut visited = vec![false; n as usize];
39 let mut order: Vec<VertexId> = Vec::with_capacity(n as usize);
40 let mut queue: VecDeque<VertexId> = VecDeque::new();
41
42 visited[root as usize] = true;
43 order.push(root);
44 queue.push_back(root);
45
46 while let Some(v) = queue.pop_front() {
47 for &w in graph.neighbors(v)? {
48 if !visited[w as usize] {
49 visited[w as usize] = true;
50 order.push(w);
51 queue.push_back(w);
52 }
53 }
54 }
55
56 Ok(order)
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 fn path_graph(n: u32) -> Graph {
64 let mut g = Graph::with_vertices(n);
65 for i in 0..n.saturating_sub(1) {
66 g.add_edge(i, i + 1).unwrap();
67 }
68 g
69 }
70
71 #[test]
72 fn empty_graph_errors_on_any_root() {
73 let g = Graph::with_vertices(0);
74 let err = bfs(&g, 0).unwrap_err();
75 assert!(matches!(
76 err,
77 crate::core::IgraphError::VertexOutOfRange { id: 0, n: 0 }
78 ));
79 }
80
81 #[test]
82 fn single_vertex_visits_self() {
83 let g = Graph::with_vertices(1);
84 assert_eq!(bfs(&g, 0).unwrap(), vec![0]);
85 }
86
87 #[test]
88 fn path_visits_in_order() {
89 let g = path_graph(5);
90 assert_eq!(bfs(&g, 0).unwrap(), vec![0, 1, 2, 3, 4]);
91 }
92
93 #[test]
94 fn bfs_layers_breadth_first_not_depth_first() {
95 let mut g = Graph::with_vertices(4);
99 g.add_edge(0, 1).unwrap();
100 g.add_edge(0, 2).unwrap();
101 g.add_edge(1, 3).unwrap();
102 let order = bfs(&g, 0).unwrap();
104 assert_eq!(order[0], 0);
105 let pos_3 = order.iter().position(|&x| x == 3).unwrap();
106 let pos_1 = order.iter().position(|&x| x == 1).unwrap();
107 let pos_2 = order.iter().position(|&x| x == 2).unwrap();
108 assert!(pos_3 > pos_1 && pos_3 > pos_2);
109 }
110
111 #[test]
112 fn unreachable_vertex_excluded() {
113 let mut g = Graph::with_vertices(3);
114 g.add_edge(0, 1).unwrap();
115 let order = bfs(&g, 0).unwrap();
117 assert_eq!(order, vec![0, 1]);
118 }
119
120 #[test]
121 fn invalid_root_errors() {
122 let g = Graph::with_vertices(2);
123 let err = bfs(&g, 5).unwrap_err();
124 match err {
125 crate::core::IgraphError::VertexOutOfRange { id, n } => {
126 assert_eq!(id, 5);
127 assert_eq!(n, 2);
128 }
129 other => panic!("unexpected error: {other:?}"),
130 }
131 }
132}