Add breadth-first search algorithms and tests
This commit is contained in:
+76
-1
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user