use std::collections::VecDeque;
use crate::utils::graph::{NodeId, Successors};
pub struct DfsIterator<'g, G: Successors> {
graph: &'g G,
stack: Vec<NodeId>,
visited: Vec<bool>,
}
impl<'g, G: Successors> DfsIterator<'g, G> {
fn new(graph: &'g G, start: NodeId) -> Self {
let node_count = graph.node_count();
if start.index() >= node_count {
return DfsIterator {
graph,
stack: Vec::new(),
visited: Vec::new(),
};
}
let mut visited = vec![false; node_count];
visited[start.index()] = true;
DfsIterator {
graph,
stack: vec![start],
visited,
}
}
}
impl<G: Successors> Iterator for DfsIterator<'_, G> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
let node = self.stack.pop()?;
if self.visited.is_empty() {
return None;
}
let successors: Vec<NodeId> = self.graph.successors(node).collect();
for &succ in successors.iter().rev() {
if !self.visited[succ.index()] {
self.visited[succ.index()] = true;
self.stack.push(succ);
}
}
Some(node)
}
}
pub fn dfs<G: Successors>(graph: &G, start: NodeId) -> DfsIterator<'_, G> {
DfsIterator::new(graph, start)
}
pub struct BfsIterator<'g, G: Successors> {
graph: &'g G,
queue: VecDeque<NodeId>,
visited: Vec<bool>,
}
impl<'g, G: Successors> BfsIterator<'g, G> {
fn new(graph: &'g G, start: NodeId) -> Self {
let node_count = graph.node_count();
if start.index() >= node_count {
return BfsIterator {
graph,
queue: VecDeque::new(),
visited: Vec::new(),
};
}
let mut visited = vec![false; node_count];
visited[start.index()] = true;
let mut queue = VecDeque::new();
queue.push_back(start);
BfsIterator {
graph,
queue,
visited,
}
}
}
impl<G: Successors> Iterator for BfsIterator<'_, G> {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
let node = self.queue.pop_front()?;
if self.visited.is_empty() {
return None;
}
for succ in self.graph.successors(node) {
if !self.visited[succ.index()] {
self.visited[succ.index()] = true;
self.queue.push_back(succ);
}
}
Some(node)
}
}
pub fn bfs<G: Successors>(graph: &G, start: NodeId) -> BfsIterator<'_, G> {
BfsIterator::new(graph, start)
}
#[allow(clippy::items_after_statements)]
pub fn postorder<G: Successors>(graph: &G, start: NodeId) -> Vec<NodeId> {
let node_count = graph.node_count();
if start.index() >= node_count {
return Vec::new();
}
let mut visited = vec![false; node_count];
let mut result = Vec::with_capacity(node_count);
#[derive(Clone, Copy)]
enum State {
Enter,
Exit,
}
let mut stack = vec![(start, State::Enter)];
while let Some((node, state)) = stack.pop() {
match state {
State::Enter => {
if visited[node.index()] {
continue;
}
visited[node.index()] = true;
stack.push((node, State::Exit));
let successors: Vec<NodeId> = graph.successors(node).collect();
for &succ in successors.iter().rev() {
if !visited[succ.index()] {
stack.push((succ, State::Enter));
}
}
}
State::Exit => {
result.push(node);
}
}
}
result
}
pub fn reverse_postorder<G: Successors>(graph: &G, start: NodeId) -> Vec<NodeId> {
let mut result = postorder(graph, start);
result.reverse();
result
}
#[cfg(test)]
mod tests {
use crate::utils::graph::{
algorithms::traversal::{bfs, dfs, postorder, reverse_postorder},
DirectedGraph, NodeId,
};
fn create_linear_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(b, c, ()).unwrap();
graph
}
fn create_diamond_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
let d = graph.add_node("D");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(a, c, ()).unwrap();
graph.add_edge(b, d, ()).unwrap();
graph.add_edge(c, d, ()).unwrap();
graph
}
fn create_cycle_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(b, c, ()).unwrap();
graph.add_edge(c, a, ()).unwrap();
graph
}
fn create_tree_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
let d = graph.add_node("D");
let e = graph.add_node("E");
let f = graph.add_node("F");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(a, c, ()).unwrap();
graph.add_edge(b, d, ()).unwrap();
graph.add_edge(b, e, ()).unwrap();
graph.add_edge(c, f, ()).unwrap();
graph
}
#[test]
fn test_dfs_linear() {
let graph = create_linear_graph();
let order: Vec<NodeId> = dfs(&graph, NodeId::new(0)).collect();
assert_eq!(order, vec![NodeId::new(0), NodeId::new(1), NodeId::new(2)]);
}
#[test]
fn test_dfs_diamond() {
let graph = create_diamond_graph();
let order: Vec<NodeId> = dfs(&graph, NodeId::new(0)).collect();
assert_eq!(order.len(), 4);
assert_eq!(order[0], NodeId::new(0));
assert!(order.contains(&NodeId::new(3)));
}
#[test]
fn test_dfs_cycle() {
let graph = create_cycle_graph();
let order: Vec<NodeId> = dfs(&graph, NodeId::new(0)).collect();
assert_eq!(order.len(), 3);
assert_eq!(order[0], NodeId::new(0));
}
#[test]
fn test_dfs_tree() {
let graph = create_tree_graph();
let order: Vec<NodeId> = dfs(&graph, NodeId::new(0)).collect();
assert_eq!(order.len(), 6);
assert_eq!(order[0], NodeId::new(0));
}
#[test]
fn test_dfs_single_node() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
let order: Vec<NodeId> = dfs(&graph, a).collect();
assert_eq!(order, vec![a]);
}
#[test]
fn test_dfs_disconnected() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let _c = graph.add_node("C");
graph.add_edge(a, b, ()).unwrap();
let order: Vec<NodeId> = dfs(&graph, a).collect();
assert_eq!(order.len(), 2);
assert!(!order.contains(&NodeId::new(2)));
}
#[test]
fn test_bfs_linear() {
let graph = create_linear_graph();
let order: Vec<NodeId> = bfs(&graph, NodeId::new(0)).collect();
assert_eq!(order, vec![NodeId::new(0), NodeId::new(1), NodeId::new(2)]);
}
#[test]
fn test_bfs_diamond() {
let graph = create_diamond_graph();
let order: Vec<NodeId> = bfs(&graph, NodeId::new(0)).collect();
assert_eq!(order.len(), 4);
assert_eq!(order[0], NodeId::new(0));
assert!(order[1] == NodeId::new(1) || order[1] == NodeId::new(2));
assert!(order[2] == NodeId::new(1) || order[2] == NodeId::new(2));
assert_eq!(order[3], NodeId::new(3));
}
#[test]
fn test_bfs_tree() {
let graph = create_tree_graph();
let order: Vec<NodeId> = bfs(&graph, NodeId::new(0)).collect();
assert_eq!(order.len(), 6);
assert_eq!(order[0], NodeId::new(0));
let level_1: Vec<NodeId> = order[1..3].to_vec();
assert!(level_1.contains(&NodeId::new(1)));
assert!(level_1.contains(&NodeId::new(2)));
let level_2: Vec<NodeId> = order[3..6].to_vec();
assert!(level_2.contains(&NodeId::new(3)));
assert!(level_2.contains(&NodeId::new(4)));
assert!(level_2.contains(&NodeId::new(5)));
}
#[test]
fn test_bfs_single_node() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
let order: Vec<NodeId> = bfs(&graph, a).collect();
assert_eq!(order, vec![a]);
}
#[test]
fn test_bfs_disconnected() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let _c = graph.add_node("C");
graph.add_edge(a, b, ()).unwrap();
let order: Vec<NodeId> = bfs(&graph, a).collect();
assert_eq!(order.len(), 2);
}
#[test]
fn test_postorder_linear() {
let graph = create_linear_graph();
let order = postorder(&graph, NodeId::new(0));
assert_eq!(order, vec![NodeId::new(2), NodeId::new(1), NodeId::new(0)]);
}
#[test]
fn test_postorder_diamond() {
let graph = create_diamond_graph();
let order = postorder(&graph, NodeId::new(0));
assert_eq!(order.len(), 4);
assert_eq!(*order.last().unwrap(), NodeId::new(0));
let d_pos = order.iter().position(|&n| n == NodeId::new(3)).unwrap();
let b_pos = order.iter().position(|&n| n == NodeId::new(1)).unwrap();
let c_pos = order.iter().position(|&n| n == NodeId::new(2)).unwrap();
assert!(d_pos < b_pos || d_pos < c_pos);
}
#[test]
fn test_postorder_tree() {
let graph = create_tree_graph();
let order = postorder(&graph, NodeId::new(0));
assert_eq!(order.len(), 6);
assert_eq!(*order.last().unwrap(), NodeId::new(0));
let d_pos = order.iter().position(|&n| n == NodeId::new(3)).unwrap();
let e_pos = order.iter().position(|&n| n == NodeId::new(4)).unwrap();
let b_pos = order.iter().position(|&n| n == NodeId::new(1)).unwrap();
assert!(d_pos < b_pos);
assert!(e_pos < b_pos);
}
#[test]
fn test_reverse_postorder_linear() {
let graph = create_linear_graph();
let order = reverse_postorder(&graph, NodeId::new(0));
assert_eq!(order, vec![NodeId::new(0), NodeId::new(1), NodeId::new(2)]);
}
#[test]
fn test_reverse_postorder_diamond() {
let graph = create_diamond_graph();
let order = reverse_postorder(&graph, NodeId::new(0));
assert_eq!(order.len(), 4);
assert_eq!(order[0], NodeId::new(0));
assert_eq!(*order.last().unwrap(), NodeId::new(3));
}
#[test]
fn test_reverse_postorder_tree() {
let graph = create_tree_graph();
let order = reverse_postorder(&graph, NodeId::new(0));
assert_eq!(order.len(), 6);
assert_eq!(order[0], NodeId::new(0));
let a_pos = order.iter().position(|&n| n == NodeId::new(0)).unwrap();
let b_pos = order.iter().position(|&n| n == NodeId::new(1)).unwrap();
let d_pos = order.iter().position(|&n| n == NodeId::new(3)).unwrap();
assert!(a_pos < b_pos);
assert!(b_pos < d_pos);
}
#[test]
fn test_reverse_postorder_with_cycle() {
let graph = create_cycle_graph();
let order = reverse_postorder(&graph, NodeId::new(0));
assert_eq!(order.len(), 3);
}
#[test]
fn test_self_loop() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
graph.add_edge(a, a, ()).unwrap();
let dfs_order: Vec<NodeId> = dfs(&graph, a).collect();
assert_eq!(dfs_order, vec![a]);
let bfs_order: Vec<NodeId> = bfs(&graph, a).collect();
assert_eq!(bfs_order, vec![a]);
let post_order = postorder(&graph, a);
assert_eq!(post_order, vec![a]);
}
#[test]
fn test_multiple_edges() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
let b = graph.add_node(());
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(a, b, ()).unwrap();
let order: Vec<NodeId> = dfs(&graph, a).collect();
assert_eq!(order, vec![a, b]);
}
#[test]
fn test_iterator_early_termination() {
let graph = create_tree_graph();
let partial: Vec<NodeId> = dfs(&graph, NodeId::new(0)).take(3).collect();
assert_eq!(partial.len(), 3);
}
}