use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::Peekable;
#[derive(Debug)]
pub struct DepthFirstSearch<V, I, F>
where
V: Copy + Debug + Eq + Hash + PartialEq,
I: Iterator<Item = V>,
F: Fn(V) -> I,
{
next_nodes: F,
visited: HashSet<V>,
frontier: Vec<I>,
}
impl<V, I, F> DepthFirstSearch<V, I, F>
where
V: Copy + Debug + Eq + Hash + PartialEq,
F: Fn(V) -> I,
I: Iterator<Item = V>,
{
pub fn new(start: impl Iterator<Item = V>, next_nodes: F) -> Self {
let mut visited = HashSet::new();
let mut frontier = Vec::new();
for v in start {
visited.insert(v);
frontier.push(next_nodes(v));
}
Self { next_nodes, visited, frontier }
}
}
impl<V, I, F> Iterator for DepthFirstSearch<V, I, F>
where
V: Copy + Debug + Eq + Hash + PartialEq,
F: Fn(V) -> I,
I: Iterator<Item = V>,
{
type Item = V;
fn next(&mut self) -> Option<V> {
while let Some(mut i) = self.frontier.pop() {
while let Some(v) = i.next() {
if !self.visited.contains(&v) {
self.frontier.push(i);
self.frontier.push((self.next_nodes)(v));
self.visited.insert(v);
return Some(v);
}
}
}
None
}
}
#[derive(Debug)]
pub struct TopologicalSearch<V, I0, I1, I2, F1, F2>
where
V: Copy + Eq + Hash + PartialEq,
I0: Iterator<Item = V>,
I1: Iterator<Item = V>,
I2: Iterator<Item = V>,
F1: Fn(V) -> I1,
F2: Fn(V) -> I2,
{
next_nodes: F1,
prev_nodes: F2,
visited: HashSet<V>,
start: I0,
frontier_fwd: Vec<I1>,
frontier_bck: HashMap<V, Peekable<I2>>,
}
impl<V, I0, I1, I2, F1, F2> TopologicalSearch<V, I0, I1, I2, F1, F2>
where
V: Copy + Debug + Eq + Hash + PartialEq,
I0: Iterator<Item = V>,
I1: Iterator<Item = V>,
I2: Iterator<Item = V>,
F1: Fn(V) -> I1,
F2: Fn(V) -> I2,
{
pub fn new(start: I0, next_nodes: F1, prev_nodes: F2) -> Self {
let visited = HashSet::new();
let frontier_fwd = Vec::new();
let frontier_bck = HashMap::new();
Self {
next_nodes,
prev_nodes,
visited,
start,
frontier_fwd,
frontier_bck,
}
}
fn can_visit(&mut self, v: V) -> bool {
if self.visited.contains(&v) {
return false;
}
let iter_bck = {
let temp1 = &mut self.frontier_bck;
let temp2 = &self.prev_nodes;
temp1.entry(v).or_insert_with(|| (temp2)(v).peekable())
};
while let Some(&u) = iter_bck.peek() {
if !self.visited.contains(&u) {
return false;
}
iter_bck.next();
}
true
}
fn visit(&mut self, v: V) -> Option<V> {
self.visited.insert(v);
self.frontier_fwd.push((self.next_nodes)(v));
Some(v)
}
}
impl<V, I0, I1, I2, F1, F2> Iterator
for TopologicalSearch<V, I0, I1, I2, F1, F2>
where
V: Copy + Debug + Eq + Hash + PartialEq,
I0: Iterator<Item = V>,
I1: Iterator<Item = V>,
I2: Iterator<Item = V>,
F1: Fn(V) -> I1,
F2: Fn(V) -> I2,
{
type Item = V;
fn next(&mut self) -> Option<V> {
loop {
while let Some(mut i) = self.frontier_fwd.pop() {
while let Some(v) = i.next() {
if self.can_visit(v) {
self.frontier_fwd.push(i);
return self.visit(v);
}
}
}
if let Some(v) = self.start.next() {
if self.can_visit(v) {
return self.visit(v);
}
} else {
return None;
}
}
}
}