Add breadth-first search algorithms and tests

This commit is contained in:
2026-06-25 21:54:49 +02:00
parent e299012948
commit 91ac925417
4 changed files with 343 additions and 1 deletions
+76 -1
View File
@@ -1,5 +1,5 @@
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::collections::{BinaryHeap, VecDeque};
use crate::maps::VertexMap;
use crate::traits::GraphTopology;
@@ -111,3 +111,78 @@ where
}
distances
}
pub struct BfsResult<V: Copy> {
pub distances: VertexMap<V, Option<u32>>,
pub predecessors: VertexMap<V, Option<V>>,
}
pub fn bfs<G>(graph: &G, source: G::Vertex) -> BfsResult<G::Vertex>
where
G: GraphTopology,
{
let mut predecessors = graph.vertex_map(None);
let (distances, _) = bfs_impl(graph, source, |neighbor, predecessor| {
predecessors[neighbor] = Some(predecessor);
true
});
BfsResult {
distances,
predecessors,
}
}
pub fn bfs_distances<G>(graph: &G, source: G::Vertex) -> VertexMap<G::Vertex, Option<u32>>
where
G: GraphTopology,
{
bfs_impl(graph, source, |_, _| true).0
}
pub fn bfs_find<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> Option<u32>
where
G: GraphTopology,
{
bfs_find_where(graph, source, |v| v == target).map(|(_, distance)| distance)
}
pub fn bfs_find_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<(G::Vertex, u32)>
where
G: GraphTopology,
P: Fn(G::Vertex) -> bool,
{
if predicate(source) {
return Some((source, 0));
}
bfs_impl(graph, source, |neighbor, _| !predicate(neighbor)).1
}
fn bfs_impl<G, F>(
graph: &G,
source: G::Vertex,
mut on_discover: F,
) -> (VertexMap<G::Vertex, Option<u32>>, Option<(G::Vertex, u32)>)
where
G: GraphTopology,
F: FnMut(G::Vertex, G::Vertex) -> bool,
{
let mut distances = graph.vertex_map(None);
let mut queue = VecDeque::new();
distances[source] = Some(0);
queue.push_back(source);
while let Some(v) = queue.pop_front() {
for neighbor in graph.adjacent_vertices(v) {
if distances[neighbor].is_none() {
let distance = distances[v].unwrap() + 1;
distances[neighbor] = Some(distance);
if !on_discover(neighbor, v) {
return (distances, Some((neighbor, distance)));
}
queue.push_back(neighbor);
}
}
}
(distances, None)
}