use crate::{
Order,
OutNeighbors,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Dfs<'a, D> {
digraph: &'a D,
stack: Vec<usize>,
visited: Vec<bool>,
}
impl<'a, D> Dfs<'a, D> {
#[must_use]
pub fn new<T>(digraph: &'a D, sources: T) -> Self
where
D: Order,
T: Iterator<Item = usize>,
{
Self {
digraph,
stack: sources.collect(),
visited: vec![false; digraph.order()],
}
}
}
impl<D> Iterator for Dfs<'_, D>
where
D: OutNeighbors,
{
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
let u = self.stack.pop()?;
let visited_ptr = self.visited.as_mut_ptr();
if unsafe { *visited_ptr.add(u) } {
return None;
}
unsafe {
*visited_ptr.add(u) = true;
}
for v in self.digraph.out_neighbors(u) {
if !unsafe { *visited_ptr.add(v) } {
self.stack.push(v);
}
}
Some(u)
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::repr::adjacency_list::fixture::{
bang_jensen_34,
bang_jensen_94,
bang_jensen_196,
kattis_builddeps,
kattis_cantinaofbabel_1,
kattis_cantinaofbabel_2,
kattis_escapewallmaria_1,
kattis_escapewallmaria_2,
kattis_escapewallmaria_3,
},
std::iter::once,
};
#[test]
fn iter_bang_jensen_196() {
let digraph = bang_jensen_196();
assert!(Dfs::new(&digraph, once(0)).eq([0, 7, 5, 6, 4, 2, 3, 1]));
}
#[test]
fn iter_bang_jensen_34() {
let digraph = bang_jensen_34();
assert!(Dfs::new(&digraph, once(0)).eq([0, 4]));
}
#[test]
fn iter_bang_jensen_94() {
let digraph = bang_jensen_94();
assert!(Dfs::new(&digraph, once(0)).eq([0, 2, 5, 4, 6, 3, 1]));
}
#[test]
fn iter_kattis_builddeps() {
let digraph = kattis_builddeps();
assert!(Dfs::new(&digraph, once(0)).eq([0, 4, 1, 3]));
}
#[test]
fn iter_kattis_cantinaofbabel_1() {
let digraph = kattis_cantinaofbabel_1();
assert!(
Dfs::new(&digraph, once(0)).eq([0, 1, 4, 3, 11, 9, 7, 10, 6, 5])
);
}
#[test]
fn iter_kattis_cantinaofbabel_2() {
let digraph = kattis_cantinaofbabel_2();
assert!(Dfs::new(&digraph, once(0)).eq([0, 1, 7, 2, 5, 6, 3, 4]));
}
#[test]
fn iter_kattis_escapewallmaria_1() {
let digraph = kattis_escapewallmaria_1();
assert!(Dfs::new(&digraph, once(5)).eq([5, 9, 13, 12, 6]));
}
#[test]
fn iter_kattis_escapewallmaria_2() {
let digraph = kattis_escapewallmaria_2();
assert!(Dfs::new(&digraph, once(5)).eq([5, 9, 6]));
}
#[test]
fn iter_kattis_escapewallmaria_3() {
let digraph = kattis_escapewallmaria_3();
assert!(Dfs::new(&digraph, once(1)).eq([1, 5, 9, 13, 12, 6, 2]));
}
}