use std::collections::{HashSet, VecDeque};
use crate::graph::capability::StableNode;
use crate::graph::Graph;
pub struct Bfs<'r, G: ?Sized, N> {
graph: &'r G,
queue: VecDeque<N>,
visited: HashSet<N>,
}
impl<'r, G> Bfs<'r, G, G::NodeIx>
where
G: Graph + ?Sized,
{
pub unsafe fn new_unchecked(graph: &'r G, start: G::NodeIx) -> Self
where
G: StableNode,
{
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
visited.insert(start);
queue.push_back(start);
Bfs {
graph,
queue,
visited,
}
}
pub fn new(graph: &'r G, start: G::NodeIx) -> Self
where
G: StableNode,
{
assert!(Graph::contains_node_index(graph, start));
unsafe { Self::new_unchecked(graph, start) }
}
pub unsafe fn add_start_unchecked(&mut self, start: G::NodeIx) {
if self.visited.insert(start) {
self.queue.push_back(start);
}
}
pub fn add_start(&mut self, start: G::NodeIx) {
assert!(Graph::contains_node_index(self.graph, start));
unsafe { self.add_start_unchecked(start) }
}
}
impl<'r, G> Iterator for Bfs<'r, G, G::NodeIx>
where
G: Graph + StableNode + ?Sized,
{
type Item = G::NodeIx;
fn next(&mut self) -> Option<G::NodeIx> {
let node = self.queue.pop_front()?;
for eix in unsafe { <G as crate::graph::GraphOperation<'_>>::edge_indices_from_unchecked(self.graph, node) } {
for endpoint in unsafe { <G as crate::graph::GraphOperation<'_>>::endpoints_unchecked(self.graph, eix) } {
if endpoint != node && self.visited.insert(endpoint) {
self.queue.push_back(endpoint);
}
}
}
Some(node)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::BTreeGraph;
fn diamond_btree() -> BTreeGraph<u32, &'static str> {
let mut g = BTreeGraph::<_, _>::default();
g.insert_node(0).unwrap();
g.insert_node(1).unwrap();
g.insert_node(2).unwrap();
g.insert_node(3).unwrap();
g.insert_edge("0->1", [0, 1]).unwrap();
g.insert_edge("0->2", [0, 2]).unwrap();
g.insert_edge("1->3", [1, 3]).unwrap();
g.insert_edge("2->3", [2, 3]).unwrap();
g
}
#[test]
fn bfs_diamond() {
let g = diamond_btree();
let order: Vec<u32> = Bfs::new(&g, 0).collect();
assert_eq!(order.len(), 4);
assert_eq!(order[0], 0);
assert!(order[1..3].contains(&1));
assert!(order[1..3].contains(&2));
assert_eq!(order[3], 3);
}
#[test]
fn bfs_single_node() {
let mut g = BTreeGraph::<u32, &str>::default();
g.insert_node(42).unwrap();
let order: Vec<u32> = Bfs::new(&g, 42).collect();
assert_eq!(order, vec![42]);
}
#[test]
#[should_panic]
fn bfs_invalid_start() {
let mut g = BTreeGraph::<u32, &str>::default();
g.insert_node(0).ok();
let _order: Vec<u32> = Bfs::new(&g, 99).collect();
}
#[test]
fn bfs_with_cycle() {
let mut g = BTreeGraph::<_, _>::default();
g.insert_node(0).unwrap();
g.insert_node(1).unwrap();
g.insert_node(2).unwrap();
g.insert_edge("0->1", [0, 1]).unwrap();
g.insert_edge("1->2", [1, 2]).unwrap();
g.insert_edge("2->0", [2, 0]).unwrap();
let order: Vec<u32> = Bfs::new(&g, 0).collect();
assert_eq!(order.len(), 3);
}
#[test]
fn bfs_multi_source() {
let mut g = BTreeGraph::<u32, &str>::default();
g.insert_node(0).unwrap();
g.insert_node(1).unwrap();
g.insert_node(2).unwrap();
let mut bfs = Bfs::new(&g, 0);
bfs.add_start(2);
let order: Vec<u32> = bfs.collect();
assert_eq!(order.len(), 2);
assert!(order.contains(&0));
assert!(order.contains(&2));
}
}