added dijkstras with test pass

This commit is contained in:
specCon18 2024-05-18 16:10:01 -04:00
parent fc92909aec
commit 4a53a4cac5

View file

@ -1,42 +1,46 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::dijkstras_shortest_path; use super::{dijkstras_shortest_path,WeightedAdjacencyList};
#[test] #[test]
fn dijkstras_shortest_path_primeagen_class_test(){ fn dijkstras_shortest_path_primeagen_class_test(){
// (B) --- (E) ---- (F) // (1) --- (4) ---- (5)
// / | | /| // / | | /|
// (A) | ------|------- | // (0) | ------|------- |
// \ |/ | | // \ |/ | |
// (C) --- (D) ---- (G) // (2) --- (3) ---- (6)
let mut graph:WeightedAdjacencyList<&str,usize> = WeightedAdjacencyList::new(); let source = 0;
graph.add_vertex("A"); let sink = 5;
graph.add_vertex("B");
graph.add_vertex("C"); let mut graph:WeightedAdjacencyList<usize,usize> = WeightedAdjacencyList::new();
graph.add_vertex("D"); graph.add_vertex(0);
graph.add_vertex("E"); graph.add_vertex(1);
graph.add_vertex("F"); graph.add_vertex(2);
graph.add_edge("A","B",3); graph.add_vertex(3);
graph.add_edge("A","C",1); graph.add_vertex(4);
graph.add_edge("B","A",3); graph.add_vertex(5);
graph.add_edge("B","C",4); graph.add_edge(0, 1, 3);
graph.add_edge("B","E",1); graph.add_edge(0, 2, 1);
graph.add_edge("C","B",4); graph.add_edge(1, 0, 3);
graph.add_edge("C","D",7); graph.add_edge(1, 2, 4);
graph.add_edge("C","A",1); graph.add_edge(1, 4, 1);
graph.add_edge("D","C",7); graph.add_edge(2, 1, 4);
graph.add_edge("D","E",5); graph.add_edge(2, 3, 7);
graph.add_edge("D","G",1); graph.add_edge(2, 0, 1);
graph.add_edge("E","B",1); graph.add_edge(3, 2, 7);
graph.add_edge("E","D",5); graph.add_edge(3, 4, 5);
graph.add_edge("E","F",2); graph.add_edge(3, 6, 1);
graph.add_edge("F","G",1); graph.add_edge(4, 1, 1);
graph.add_edge("F","E",2); graph.add_edge(4, 3, 5);
graph.add_edge("F","C",18); graph.add_edge(4, 5, 2);
graph.add_edge("G","D",1); graph.add_edge(5, 6, 1);
graph.add_edge("G","F",1); graph.add_edge(5, 4, 2);
dijkstras_shortest_path(source,sink,graph); graph.add_edge(5, 2, 18);
graph.add_edge(6, 3, 1);
graph.add_edge(6, 5, 1);
let path = dijkstras_shortest_path(source,sink,graph.clone());
assert_eq!(path.unwrap(), vec![0, 1, 4, 5]);
} }
} }
// Define a struct to represent the adjacency list with weighted edges // Define a struct to represent the adjacency list with weighted edges
@ -44,6 +48,18 @@ pub struct WeightedAdjacencyList<T, W> {
vertices: HashMap<T, HashMap<T, W>>, vertices: HashMap<T, HashMap<T, W>>,
} }
impl<T, W> Clone for WeightedAdjacencyList<T, W>
where
T: Clone,
W: Clone,
{
fn clone(&self) -> Self {
WeightedAdjacencyList {
vertices: self.vertices.clone(),
}
}
}
impl<T, W> WeightedAdjacencyList<T, W> impl<T, W> WeightedAdjacencyList<T, W>
where where
T: std::hash::Hash + Eq + Clone, T: std::hash::Hash + Eq + Clone,
@ -79,24 +95,65 @@ where
fn get_neighbors(&self, vertex: &T) -> Option<&HashMap<T, W>> { fn get_neighbors(&self, vertex: &T) -> Option<&HashMap<T, W>> {
self.vertices.get(vertex) self.vertices.get(vertex)
} }
// Method to get the number of vertices in the adjacency list
fn len(&self) -> usize {
self.vertices.len()
}
} }
pub fn dijkstras_shortest_path(
source: usize,
sink: usize,
graph: WeightedAdjacencyList<usize, usize>,
) -> Option<Vec<usize>> {
let mut seen: Vec<bool> = vec![false; graph.len()];
let mut prev: Vec<usize> = vec![usize::MAX; graph.len()];
let mut dists: Vec<f64> = vec![f64::INFINITY; graph.len()];
dists[source] = 0.0;
while has_unvisited(&seen, &dists) {
let curr = get_lowest_unvisited(&seen, &dists);
seen[curr] = true;
if let Some(adjs) = graph.get_neighbors(&curr) {
for (&to, &weight) in adjs.iter() {
if !seen[to] {
let new_dist = dists[curr] + weight as f64;
if new_dist < dists[to] {
dists[to] = new_dist;
prev[to] = curr;
}
}
}
}
}
// Check if sink is unreachable
if prev[sink] == usize::MAX {
return None;
}
// Reconstruct shortest path
let mut path = Vec::new();
let mut curr = sink;
while curr != usize::MAX {
path.push(curr);
curr = prev[curr];
}
path.reverse();
Some(path)
}
fn has_unvisited(seen: &[bool], dists: &[f64]) -> bool { fn has_unvisited(seen: &[bool], dists: &[f64]) -> bool {
return seen.iter().enumerate().any(|(i, &s)| !s && dists[i] < f64::INFINITY); seen.iter().enumerate().any(|(i, &s)| !s && dists[i] < f64::INFINITY)
} }
fn get_lowest_unvisited(seen: &[bool], dists: &[f64]) -> usize { fn get_lowest_unvisited(seen: &[bool], dists: &[f64]) -> usize {
let mut idx = usize::MAX; let mut idx = usize::MAX;
let mut lowest_distance = f64::INFINITY; let mut lowest_distance = f64::INFINITY;
for (i, &is_seen) in seen.iter().enumerate() { for (i, &is_seen) in seen.iter().enumerate() {
if is_seen { if !is_seen && dists[i] < lowest_distance {
continue;
}
if lowest_distance > dists[i] {
lowest_distance = dists[i]; lowest_distance = dists[i];
idx = i; idx = i;
} }
} }
idx idx
} }
pub fn dijkstras_shortest_path(source:usize,sink:usize,mut graph:WeightedAdjacencyList<&str,usize>){
}