graaf/algo/bfs.rs
1//! Breadth-first search.
2//!
3//! Breadth-first search explores an unweighted digraph's vertices in the order
4//! of their distance from a source.
5//!
6//! The time complexity is `O(v + a)`, where `v` is the digraph's order and
7//! `a` is the digraph's size.
8//!
9//! # Examples
10//!
11//! ## Single source
12//!
13//! The path from vertex `0` is red. `t` denotes the iteration indices.
14//!
15//! 
16//!
17//! ```
18//! use {
19//! graaf::{
20//! AddArc,
21//! AdjacencyList,
22//! Bfs,
23//! Empty,
24//! },
25//! std::iter::once,
26//! };
27//!
28//! let mut digraph = AdjacencyList::empty(6);
29//!
30//! digraph.add_arc(0, 1);
31//! digraph.add_arc(1, 2);
32//! digraph.add_arc(1, 4);
33//! digraph.add_arc(2, 5);
34//! digraph.add_arc(3, 0);
35//!
36//! assert!(Bfs::new(&digraph, once(0)).eq([0, 1, 2, 4, 5]));
37//! ```
38//!
39//! ## Multiple sources
40//!
41//! The path from vertex `0` is red. The path from vertex `1` is blue.
42//!
43//! 
44//!
45//! ```
46//! use graaf::{
47//! AddArc,
48//! AdjacencyList,
49//! Bfs,
50//! Empty,
51//! };
52//!
53//! let mut digraph = AdjacencyList::empty(8);
54//!
55//! digraph.add_arc(0, 1);
56//! digraph.add_arc(1, 2);
57//! digraph.add_arc(1, 4);
58//! digraph.add_arc(2, 3);
59//! digraph.add_arc(2, 5);
60//! digraph.add_arc(2, 6);
61//! digraph.add_arc(3, 0);
62//! digraph.add_arc(6, 5);
63//! digraph.add_arc(6, 7);
64//! digraph.add_arc(7, 6);
65//!
66//! assert!(
67//! Bfs::new(&digraph, [3, 7].into_iter()).eq([3, 7, 0, 6, 1, 5, 2, 4])
68//! );
69//! ```
70
71use {
72 crate::{
73 Order,
74 OutNeighbors,
75 },
76 std::collections::VecDeque,
77};
78
79/// Breadth-first search.
80///
81/// Breadth-first search explores an unweighted digraph's vertices in the order
82/// of their distance from a source.
83///
84/// # Examples
85///
86/// The path from vertex `0` is red. `t` denotes the iteration indices.
87///
88/// 
89///
90/// ```
91/// use {
92/// graaf::{
93/// AddArc,
94/// AdjacencyList,
95/// Bfs,
96/// Empty,
97/// },
98/// std::iter::once,
99/// };
100///
101/// let mut digraph = AdjacencyList::empty(6);
102///
103/// digraph.add_arc(0, 1);
104/// digraph.add_arc(1, 2);
105/// digraph.add_arc(1, 4);
106/// digraph.add_arc(2, 5);
107/// digraph.add_arc(3, 0);
108///
109/// assert!(Bfs::new(&digraph, once(0)).eq([0, 1, 2, 4, 5]));
110/// ```
111///
112/// ## Multiple sources
113///
114/// The path from vertex `0` is red. The path from vertex `1` is blue.
115///
116/// 
117///
118/// ```
119/// use graaf::{
120/// AddArc,
121/// AdjacencyList,
122/// Bfs,
123/// Empty,
124/// };
125///
126/// let mut digraph = AdjacencyList::empty(8);
127///
128/// digraph.add_arc(0, 1);
129/// digraph.add_arc(1, 2);
130/// digraph.add_arc(1, 4);
131/// digraph.add_arc(2, 3);
132/// digraph.add_arc(2, 5);
133/// digraph.add_arc(2, 6);
134/// digraph.add_arc(3, 0);
135/// digraph.add_arc(6, 5);
136/// digraph.add_arc(6, 7);
137/// digraph.add_arc(7, 6);
138///
139/// assert!(
140/// Bfs::new(&digraph, [3, 7].into_iter()).eq([3, 7, 0, 6, 1, 5, 2, 4])
141/// );
142/// ```
143#[derive(Clone, Debug, Eq, PartialEq)]
144pub struct Bfs<'a, D> {
145 digraph: &'a D,
146 queue: VecDeque<usize>,
147 visited: Vec<bool>,
148}
149
150impl<'a, D> Bfs<'a, D> {
151 /// Construct a new breadth-first search.
152 ///
153 /// # Arguments
154 ///
155 /// * `digraph`: The digraph.
156 /// * `sources`: The source vertices.
157 #[must_use]
158 pub fn new<T>(digraph: &'a D, sources: T) -> Self
159 where
160 D: Order,
161 T: Iterator<Item = usize> + Clone,
162 {
163 let order = digraph.order();
164 let mut queue = VecDeque::with_capacity(order);
165 let mut visited = vec![false; order];
166 let visited_ptr = visited.as_mut_ptr();
167
168 for u in sources {
169 queue.push_back(u);
170
171 unsafe {
172 *visited_ptr.add(u) = true;
173 }
174 }
175
176 Self {
177 digraph,
178 queue,
179 visited,
180 }
181 }
182}
183
184impl<D> Iterator for Bfs<'_, D>
185where
186 D: OutNeighbors,
187{
188 type Item = usize;
189
190 fn next(&mut self) -> Option<Self::Item> {
191 let u = self.queue.pop_front()?;
192 let visited_ptr = self.visited.as_mut_ptr();
193
194 for v in self.digraph.out_neighbors(u) {
195 let visited_v = unsafe { visited_ptr.add(v) };
196
197 unsafe {
198 if !*visited_v {
199 *visited_v = true;
200
201 self.queue.push_back(v);
202 }
203 }
204 }
205
206 Some(u)
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use {
213 super::*,
214 crate::repr::adjacency_list::fixture::{
215 bang_jensen_34,
216 bang_jensen_94,
217 bang_jensen_196,
218 kattis_builddeps,
219 kattis_cantinaofbabel_1,
220 kattis_cantinaofbabel_2,
221 kattis_escapewallmaria_1,
222 kattis_escapewallmaria_2,
223 kattis_escapewallmaria_3,
224 },
225 std::iter::once,
226 };
227
228 #[test]
229 fn iter_bang_jensen_196() {
230 let digraph = bang_jensen_196();
231
232 assert!(Bfs::new(&digraph, once(0)).eq([0, 1, 4, 7, 2, 5, 3, 6]));
233 }
234
235 #[test]
236 fn iter_bang_jensen_34() {
237 let digraph = bang_jensen_34();
238
239 assert!(Bfs::new(&digraph, once(0)).eq([0, 4]));
240 }
241
242 #[test]
243 fn iter_bang_jensen_94() {
244 let digraph = bang_jensen_94();
245
246 assert!(Bfs::new(&digraph, once(0)).eq([0, 1, 2, 3, 4, 5, 6]));
247 }
248
249 #[test]
250 fn iter_kattis_builddeps() {
251 let digraph = kattis_builddeps();
252
253 assert!(Bfs::new(&digraph, once(0)).eq([0, 3, 4, 1]));
254 }
255
256 #[test]
257 fn iter_kattis_cantinaofbabel_1() {
258 let digraph = kattis_cantinaofbabel_1();
259
260 assert!(
261 Bfs::new(&digraph, once(0))
262 .eq([0, 1, 2, 4, 3, 5, 7, 10, 11, 6, 9])
263 );
264 }
265
266 #[test]
267 fn iter_kattis_cantinaofbabel_2() {
268 let digraph = kattis_cantinaofbabel_2();
269
270 assert!(Bfs::new(&digraph, once(0)).eq([0, 1, 7, 2, 5, 3, 6, 4]));
271 }
272
273 #[test]
274 fn iter_kattis_escapewallmaria_1() {
275 let digraph = kattis_escapewallmaria_1();
276
277 assert!(Bfs::new(&digraph, once(5)).eq([5, 6, 9, 13, 12]));
278 }
279
280 #[test]
281 fn iter_kattis_escapewallmaria_2() {
282 let digraph = kattis_escapewallmaria_2();
283
284 assert!(Bfs::new(&digraph, once(5)).eq([5, 6, 9]));
285 }
286
287 #[test]
288 fn iter_kattis_escapewallmaria_3() {
289 let digraph = kattis_escapewallmaria_3();
290
291 assert!(Bfs::new(&digraph, once(1)).eq([1, 2, 5, 6, 9, 13, 12]));
292 }
293}