use crate::graph::GraphRef;
pub fn bfs_distances<G: GraphRef>(graph: &G, source: usize) -> Vec<Option<usize>> {
let n = graph.node_count();
let mut dist = vec![None; n];
if source >= n {
return dist;
}
dist[source] = Some(0);
let mut queue = std::collections::VecDeque::new();
queue.push_back(source);
while let Some(u) = queue.pop_front() {
let d = dist[u].unwrap();
for &v in graph.neighbors_ref(u) {
if v < n && dist[v].is_none() {
dist[v] = Some(d + 1);
queue.push_back(v);
}
}
}
dist
}
pub fn bfs_path<G: GraphRef>(graph: &G, source: usize, target: usize) -> Option<Vec<usize>> {
let n = graph.node_count();
if source >= n || target >= n {
return None;
}
if source == target {
return Some(vec![source]);
}
let mut prev = vec![usize::MAX; n];
prev[source] = source;
let mut queue = std::collections::VecDeque::new();
queue.push_back(source);
while let Some(u) = queue.pop_front() {
for &v in graph.neighbors_ref(u) {
if v < n && prev[v] == usize::MAX {
prev[v] = u;
if v == target {
let mut path = vec![target];
let mut cur = target;
while cur != source {
cur = prev[cur];
path.push(cur);
}
path.reverse();
return Some(path);
}
queue.push_back(v);
}
}
}
None
}
pub fn dijkstra_distances<G: crate::graph::WeightedGraphRef>(
graph: &G,
source: usize,
) -> Vec<Option<f32>> {
let n = graph.node_count();
let mut dist: Vec<Option<f32>> = vec![None; n];
if source >= n {
return dist;
}
dist[source] = Some(0.0);
use ordered_float::OrderedFloat;
let mut heap = std::collections::BinaryHeap::new();
heap.push(std::cmp::Reverse((OrderedFloat(0.0f32), source)));
while let Some(std::cmp::Reverse((OrderedFloat(d), u))) = heap.pop() {
if let Some(current) = dist[u] {
if d > current {
continue;
}
}
let (neighbors, weights) = graph.neighbors_and_weights_ref(u);
for (&v, &w) in neighbors.iter().zip(weights.iter()) {
if v >= n {
continue;
}
let new_dist = d + w;
let better = match dist[v] {
Some(old) => new_dist < old,
None => true,
};
if better {
dist[v] = Some(new_dist);
heap.push(std::cmp::Reverse((OrderedFloat(new_dist), v)));
}
}
}
dist
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::{GraphRef, WeightedGraphRef};
struct VecGraph {
adj: Vec<Vec<usize>>,
}
impl GraphRef for VecGraph {
fn node_count(&self) -> usize {
self.adj.len()
}
fn neighbors_ref(&self, node: usize) -> &[usize] {
&self.adj[node]
}
}
struct WGraph {
neighbors: Vec<Vec<usize>>,
weights: Vec<Vec<f32>>,
}
impl WeightedGraphRef for WGraph {
fn node_count(&self) -> usize {
self.neighbors.len()
}
fn neighbors_and_weights_ref(&self, node: usize) -> (&[usize], &[f32]) {
(&self.neighbors[node], &self.weights[node])
}
}
#[test]
fn bfs_chain() {
let g = VecGraph {
adj: vec![vec![1], vec![0, 2], vec![1, 3], vec![2]],
};
let d = bfs_distances(&g, 0);
assert_eq!(d, vec![Some(0), Some(1), Some(2), Some(3)]);
}
#[test]
fn bfs_unreachable() {
let g = VecGraph {
adj: vec![vec![1], vec![0], vec![], vec![]],
};
let d = bfs_distances(&g, 0);
assert_eq!(d[2], None);
assert_eq!(d[3], None);
}
#[test]
fn bfs_path_exists() {
let g = VecGraph {
adj: vec![vec![1], vec![0, 2], vec![1, 3], vec![2]],
};
let path = bfs_path(&g, 0, 3).unwrap();
assert_eq!(path, vec![0, 1, 2, 3]);
}
#[test]
fn bfs_path_no_path() {
let g = VecGraph {
adj: vec![vec![1], vec![0], vec![3], vec![2]],
};
assert!(bfs_path(&g, 0, 2).is_none());
}
#[test]
fn bfs_path_same_node() {
let g = VecGraph {
adj: vec![vec![1], vec![0]],
};
assert_eq!(bfs_path(&g, 0, 0), Some(vec![0]));
}
#[test]
fn dijkstra_weighted() {
let g = WGraph {
neighbors: vec![vec![1, 2], vec![0, 2], vec![0, 1, 3], vec![2]],
weights: vec![
vec![1.0, 4.0],
vec![1.0, 2.0],
vec![4.0, 2.0, 1.0],
vec![1.0],
],
};
let d = dijkstra_distances(&g, 0);
assert_eq!(d[0], Some(0.0));
assert_eq!(d[1], Some(1.0));
assert_eq!(d[2], Some(3.0)); assert_eq!(d[3], Some(4.0)); }
#[test]
fn dijkstra_unreachable() {
let g = WGraph {
neighbors: vec![vec![1], vec![0], vec![], vec![]],
weights: vec![vec![1.0], vec![1.0], vec![], vec![]],
};
let d = dijkstra_distances(&g, 0);
assert_eq!(d[2], None);
}
}