From 4a53a4cac552e4439ea6c6a32c0fa84633e629ca Mon Sep 17 00:00:00 2001 From: specCon18 Date: Sat, 18 May 2024 16:10:01 -0400 Subject: [PATCH] added dijkstras with test pass --- src/dijkstras.rs | 137 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 40 deletions(-) diff --git a/src/dijkstras.rs b/src/dijkstras.rs index 7d37efc..c07578d 100644 --- a/src/dijkstras.rs +++ b/src/dijkstras.rs @@ -1,42 +1,46 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; #[cfg(test)] mod tests { - use super::dijkstras_shortest_path; + use super::{dijkstras_shortest_path,WeightedAdjacencyList}; #[test] fn dijkstras_shortest_path_primeagen_class_test(){ - // (B) --- (E) ---- (F) + // (1) --- (4) ---- (5) // / | | /| - // (A) | ------|------- | + // (0) | ------|------- | // \ |/ | | - // (C) --- (D) ---- (G) - let mut graph:WeightedAdjacencyList<&str,usize> = WeightedAdjacencyList::new(); - graph.add_vertex("A"); - graph.add_vertex("B"); - graph.add_vertex("C"); - graph.add_vertex("D"); - graph.add_vertex("E"); - graph.add_vertex("F"); - graph.add_edge("A","B",3); - graph.add_edge("A","C",1); - graph.add_edge("B","A",3); - graph.add_edge("B","C",4); - graph.add_edge("B","E",1); - graph.add_edge("C","B",4); - graph.add_edge("C","D",7); - graph.add_edge("C","A",1); - graph.add_edge("D","C",7); - graph.add_edge("D","E",5); - graph.add_edge("D","G",1); - graph.add_edge("E","B",1); - graph.add_edge("E","D",5); - graph.add_edge("E","F",2); - graph.add_edge("F","G",1); - graph.add_edge("F","E",2); - graph.add_edge("F","C",18); - graph.add_edge("G","D",1); - graph.add_edge("G","F",1); - dijkstras_shortest_path(source,sink,graph); + // (2) --- (3) ---- (6) + let source = 0; + let sink = 5; + + let mut graph:WeightedAdjacencyList = WeightedAdjacencyList::new(); + graph.add_vertex(0); + graph.add_vertex(1); + graph.add_vertex(2); + graph.add_vertex(3); + graph.add_vertex(4); + graph.add_vertex(5); + graph.add_edge(0, 1, 3); + graph.add_edge(0, 2, 1); + graph.add_edge(1, 0, 3); + graph.add_edge(1, 2, 4); + graph.add_edge(1, 4, 1); + graph.add_edge(2, 1, 4); + graph.add_edge(2, 3, 7); + graph.add_edge(2, 0, 1); + graph.add_edge(3, 2, 7); + graph.add_edge(3, 4, 5); + graph.add_edge(3, 6, 1); + graph.add_edge(4, 1, 1); + graph.add_edge(4, 3, 5); + graph.add_edge(4, 5, 2); + graph.add_edge(5, 6, 1); + graph.add_edge(5, 4, 2); + 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 @@ -44,6 +48,18 @@ pub struct WeightedAdjacencyList { vertices: HashMap>, } +impl Clone for WeightedAdjacencyList +where + T: Clone, + W: Clone, +{ + fn clone(&self) -> Self { + WeightedAdjacencyList { + vertices: self.vertices.clone(), + } + } +} + impl WeightedAdjacencyList where T: std::hash::Hash + Eq + Clone, @@ -79,24 +95,65 @@ where fn get_neighbors(&self, vertex: &T) -> Option<&HashMap> { 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, +) -> Option> { + let mut seen: Vec = vec![false; graph.len()]; + let mut prev: Vec = vec![usize::MAX; graph.len()]; + let mut dists: Vec = 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 { - 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 { let mut idx = usize::MAX; let mut lowest_distance = f64::INFINITY; for (i, &is_seen) in seen.iter().enumerate() { - if is_seen { - continue; - } - if lowest_distance > dists[i] { + if !is_seen && dists[i] < lowest_distance { lowest_distance = dists[i]; idx = i; } } idx } -pub fn dijkstras_shortest_path(source:usize,sink:usize,mut graph:WeightedAdjacencyList<&str,usize>){ - -}