Skip to content

Commit cca0847

Browse files
Add Dijkstra's algorithm implementation and tests
1 parent 1ee7c81 commit cca0847

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,7 @@ path = "adventofcode/2019/d8/d8.rs"
3737
[[bin]]
3838
name = "aoc-2019-d24"
3939
path = "adventofcode/2019/d24/d24.rs"
40+
41+
[[bin]]
42+
name = "dijkstra"
43+
path = "graph/dijkstra.rs"

graph/dijkstra.rs

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
use std::collections::{BinaryHeap, HashMap};
2+
use std::cmp::Ordering;
3+
4+
// Define the Graph structure
5+
struct Graph {
6+
edges: HashMap<usize, Vec<(usize, usize)>>,
7+
}
8+
9+
// Define the Node structure for the priority queue
10+
#[derive(Copy, Clone, Eq, PartialEq)]
11+
struct Node {
12+
cost: usize,
13+
vertex: usize,
14+
}
15+
16+
// Implement Ord and PartialOrd for Node to use in BinaryHeap
17+
impl Ord for Node {
18+
fn cmp(&self, other: &Self) -> Ordering {
19+
other.cost.cmp(&self.cost)
20+
}
21+
}
22+
23+
impl PartialOrd for Node {
24+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
25+
Some(self.cmp(other))
26+
}
27+
}
28+
29+
impl Graph {
30+
// Constructor for Graph
31+
fn new() -> Self {
32+
Graph {
33+
edges: HashMap::new(),
34+
}
35+
}
36+
37+
// Method to add an edge to the graph
38+
fn add_edge(&mut self, from: usize, to: usize, cost: usize) {
39+
self.edges.entry(from).or_insert(Vec::new()).push((to, cost));
40+
self.edges.entry(to).or_insert(Vec::new()); // Ensure all vertices are in the map
41+
}
42+
43+
// Dijkstra's algorithm to find the shortest path
44+
fn dijkstra(&self, start: usize, end: usize) -> Option<(Vec<usize>, usize)> {
45+
let mut distances: HashMap<usize, usize> = HashMap::new();
46+
let mut heap = BinaryHeap::new();
47+
let mut predecessors: HashMap<usize, usize> = HashMap::new();
48+
49+
// Initialize distances
50+
for &vertex in self.edges.keys() {
51+
distances.insert(vertex, std::usize::MAX);
52+
}
53+
distances.insert(start, 0);
54+
heap.push(Node { cost: 0, vertex: start });
55+
56+
while let Some(Node { cost, vertex }) = heap.pop() {
57+
if vertex == end {
58+
let mut path = vec![end];
59+
let mut current = end;
60+
while let Some(&pred) = predecessors.get(&current) {
61+
path.push(pred);
62+
current = pred;
63+
}
64+
path.reverse();
65+
return Some((path, cost));
66+
}
67+
68+
if cost > distances[&vertex] {
69+
continue;
70+
}
71+
72+
if let Some(neighbors) = self.edges.get(&vertex) {
73+
for &(neighbor, edge_cost) in neighbors {
74+
let new_cost = cost + edge_cost;
75+
if new_cost < distances[&neighbor] {
76+
distances.insert(neighbor, new_cost);
77+
predecessors.insert(neighbor, vertex);
78+
heap.push(Node { cost: new_cost, vertex: neighbor });
79+
}
80+
}
81+
}
82+
}
83+
84+
None // No path found
85+
}
86+
}
87+
88+
#[cfg(test)]
89+
mod tests {
90+
use super::*;
91+
92+
#[test]
93+
fn test_simple_path() {
94+
let mut graph = Graph::new();
95+
graph.add_edge(0, 1, 4);
96+
graph.add_edge(1, 2, 3);
97+
graph.add_edge(2, 3, 2);
98+
99+
let result = graph.dijkstra(0, 3);
100+
assert_eq!(result, Some((vec![0, 1, 2, 3], 9)));
101+
}
102+
103+
#[test]
104+
fn test_multiple_paths() {
105+
let mut graph = Graph::new();
106+
graph.add_edge(0, 1, 4);
107+
graph.add_edge(0, 2, 1);
108+
graph.add_edge(1, 3, 1);
109+
graph.add_edge(2, 1, 2);
110+
graph.add_edge(2, 3, 5);
111+
112+
let result = graph.dijkstra(0, 3);
113+
assert_eq!(result, Some((vec![0, 2, 1, 3], 4)));
114+
}
115+
116+
#[test]
117+
fn test_no_path() {
118+
let mut graph = Graph::new();
119+
graph.add_edge(0, 1, 4);
120+
graph.add_edge(1, 2, 3);
121+
graph.add_edge(3, 4, 2);
122+
123+
let result = graph.dijkstra(0, 4);
124+
assert_eq!(result, None);
125+
}
126+
127+
#[test]
128+
fn test_graph_with_cycle() {
129+
let mut graph = Graph::new();
130+
graph.add_edge(0, 1, 1);
131+
graph.add_edge(1, 2, 2);
132+
graph.add_edge(2, 3, 3);
133+
graph.add_edge(3, 1, 1);
134+
graph.add_edge(3, 4, 4);
135+
136+
let result = graph.dijkstra(0, 4);
137+
assert_eq!(result, Some((vec![0, 1, 2, 3, 4], 10)));
138+
}
139+
140+
#[test]
141+
fn test_large_graph() {
142+
let mut graph = Graph::new();
143+
for i in 0..1000 {
144+
graph.add_edge(i, i + 1, 1);
145+
}
146+
graph.add_edge(0, 1000, 999);
147+
148+
let result = graph.dijkstra(0, 1000);
149+
assert_eq!(result, Some((vec![0, 1000], 999)));
150+
}
151+
}

0 commit comments

Comments
 (0)