add a depth_first_search helper function

This commit is contained in:
Niko Matsakis 2019-06-11 16:29:27 -04:00
parent 4c91bb9571
commit 7fd0db7dd3
3 changed files with 49 additions and 1 deletions

View File

@ -1,5 +1,6 @@
use super::super::indexed_vec::IndexVec;
use super::{DirectedGraph, WithSuccessors, WithNumNodes};
use super::{DirectedGraph, WithNumNodes, WithSuccessors};
use crate::bit_set::BitSet;
#[cfg(test)]
mod test;
@ -51,3 +52,36 @@ pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
vec.reverse();
vec
}
/// A "depth-first search" iterator for a directed graph.
pub struct DepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
graph: &'graph G,
stack: Vec<G::Node>,
visited: BitSet<G::Node>,
}
impl<G> DepthFirstSearch<'graph, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
pub fn new(graph: &'graph G, start_node: G::Node) -> Self {
Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
}
}
impl<G> Iterator for DepthFirstSearch<'_, G>
where
G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
type Item = G::Node;
fn next(&mut self) -> Option<G::Node> {
let DepthFirstSearch { stack, visited, graph } = self;
let n = stack.pop()?;
stack.extend(graph.successors(n).filter(|&m| visited.insert(m)));
Some(n)
}
}

View File

@ -30,6 +30,13 @@ where
&'graph self,
node: Self::Node,
) -> <Self as GraphSuccessors<'graph>>::Iter;
fn depth_first_search(&self, from: Self::Node) -> iterate::DepthFirstSearch<'_, Self>
where
Self: WithNumNodes,
{
iterate::DepthFirstSearch::new(self, from)
}
}
pub trait GraphSuccessors<'graph> {

View File

@ -44,3 +44,10 @@ fn succesors() {
assert_eq!(graph.successors(5), &[1]);
assert_eq!(graph.successors(6), &[]);
}
#[test]
fn dfs() {
let graph = create_graph();
let dfs: Vec<_> = graph.depth_first_search(0).collect();
assert_eq!(dfs, vec![0, 1, 3, 4, 2]);
}