use std::fs;
use super::{Graph, Path, Search};
pub struct BreadthFirstSearch {
marked: Vec<bool>,
edge_to: Vec<usize>,
s: usize,
count: usize,
}
impl BreadthFirstSearch {
pub fn new(g: &Graph, s: usize) -> Self {
let mut marked = Vec::with_capacity(g.vertex_count());
let mut edge_to = Vec::with_capacity(g.vertex_count());
for _ in 0..g.vertex_count() {
marked.push(false);
edge_to.push(usize::MAX);
}
let count = 0;
let mut bfs = BreadthFirstSearch {
marked,
edge_to,
s,
count,
};
bfs.bfs(g, s);
bfs
}
fn bfs(&mut self, g: &Graph, s: usize) {
let mut queue = std::collections::VecDeque::new();
self.marked[s] = true;
queue.push_back(s);
while let Some(v) = queue.pop_front() {
self.count += 1;
for w in g.adj(v).clone() {
if !self.marked[w] {
self.edge_to[w] = v;
self.marked[w] = true;
queue.push_back(w);
}
}
}
}
pub fn print_dot(&self, path: &str) {
let mut graph = r#"digraph{
label="graph"
bgcolor=grey
shape=circle
"#
.to_string();
for (t, f) in self
.edge_to
.iter()
.enumerate()
.filter(|(_, w)| **w != usize::MAX)
{
graph.push_str(&format!("{} -> {}\n", f, t));
}
graph.push('}');
let _ = fs::write(path, graph);
}
}
impl Search for BreadthFirstSearch {
fn marked(&self, v: usize) -> bool {
self.marked[v]
}
fn count(&self) -> usize {
self.count
}
}
impl Path for BreadthFirstSearch {
fn has_path_to(&self, v: usize) -> bool {
self.marked(v)
}
fn path_to(&self, v: usize) -> Option<Box<dyn Iterator<Item = usize>>> {
if !self.has_path_to(v) {
return None;
}
let mut ans = Vec::new();
let mut p = v;
while p != self.s {
ans.push(p);
p = self.edge_to[p];
}
ans.push(self.s);
Some(Box::new(ans.into_iter()))
}
}
#[cfg(test)]
mod test {
use crate::graph::{Graph, Path, Search};
use super::BreadthFirstSearch;
#[test]
fn test() {
let mut g = Graph::new(10);
g.add_edge(0, 1);
g.add_edge(1, 4);
g.add_edge(3, 1);
g.add_edge(3, 4);
let search = BreadthFirstSearch::new(&g, 0);
assert_eq!(search.marked(4), true);
assert_eq!(search.count(), 4);
assert_ne!(search.has_path_to(2), true);
assert_eq!(search.has_path_to(4), true);
assert!(search.path_to(2).is_none());
assert_eq!(
search.path_to(3).unwrap().collect::<Vec<usize>>(),
vec![3, 1, 0]
);
assert_eq!(
search.path_to(4).unwrap().collect::<Vec<usize>>(),
vec![4, 1, 0]
);
assert_eq!(
search.path_to(1).unwrap().collect::<Vec<usize>>(),
vec![1, 0]
);
assert_eq!(search.path_to(0).unwrap().collect::<Vec<usize>>(), vec![0]);
}
}