use std::fs;
use super::{Graph, Path, Search};
pub struct DepthFirstSearch {
marked: Vec<bool>,
edge_to: Vec<usize>,
s: usize,
count: usize,
}
impl DepthFirstSearch {
pub fn new(g: &Graph, s: usize) -> Self {
let marked: Vec<bool> = vec![false; g.vertex_count()];
let count = 0;
let edge_to = vec![usize::MAX; g.vertex_count()];
let mut search = DepthFirstSearch {
s,
marked,
count,
edge_to,
};
search.dfs(g, s);
search
}
fn dfs(&mut self, g: &Graph, v: usize) {
self.marked[v] = true;
self.count += 1;
let a = g.adj(v).iter();
let mut a = a.collect::<Vec<&usize>>();
a.sort();
for w in a {
if !self.marked[*w] {
self.edge_to[*w] = v;
self.dfs(g, *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 DepthFirstSearch {
fn marked(&self, v: usize) -> bool {
self.marked[v]
}
fn count(&self) -> usize {
self.count
}
}
impl Path for DepthFirstSearch {
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::DepthFirstSearch;
#[test]
fn test() {
let mut g = Graph::new(10);
g.add_edge(0, 1);
g.add_edge(3, 1);
g.add_edge(1, 4);
g.add_edge(3, 4);
let search = DepthFirstSearch::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_eq!(
search.path_to(3).unwrap().collect::<Vec<usize>>(),
vec![3, 1, 0]
);
assert!(search.path_to(2).is_none());
assert_eq!(
search.path_to(4).unwrap().collect::<Vec<usize>>(),
vec![4, 3, 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]);
}
}