Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/advent-of-code-2021
Path: blob/main/src/dijkstra.rs
97 views
1
use std::cmp::Ordering;
2
use std::collections::{BinaryHeap, HashMap};
3
use std::hash::Hash;
4
5
// Calculates the shortest path between two nodes using Dijkstra's algorithm.
6
pub fn shortest_path<T, FT, IT>(start: &T, end: &T, successors: FT) -> Option<usize>
7
where
8
T: Eq + Hash + Clone,
9
FT: Fn(&T) -> IT,
10
IT: IntoIterator<Item = (T, usize)>,
11
{
12
let mut unvisited = BinaryHeap::new();
13
let mut distances = HashMap::new();
14
15
distances.insert(start.clone(), 0);
16
unvisited.push(Node {
17
value: start.clone(),
18
cost: 0,
19
});
20
21
while let Some(min_cost_node) = unvisited.pop() {
22
let Node { value, cost } = min_cost_node;
23
24
if &value == end {
25
return Some(cost);
26
}
27
28
if distances[&value] < cost {
29
continue;
30
}
31
32
for (succ, succ_cost) in successors(&value) {
33
let path_cost = cost + succ_cost;
34
if path_cost < *distances.get(&succ).unwrap_or(&usize::MAX) {
35
distances.insert(succ.clone(), path_cost);
36
unvisited.push(Node {
37
value: succ,
38
cost: path_cost,
39
});
40
}
41
}
42
}
43
None
44
}
45
46
#[derive(PartialEq, Eq)]
47
struct Node<T: Eq> {
48
value: T,
49
cost: usize,
50
}
51
52
impl<T: Eq> Ord for Node<T> {
53
fn cmp(&self, other: &Self) -> Ordering {
54
// Compare cost in the other way so the binary heap is min-sorted.
55
other.cost.cmp(&self.cost)
56
}
57
}
58
59
// Rust requires this for some reason too.
60
impl<T: Eq> PartialOrd for Node<T> {
61
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
62
Some(self.cmp(other))
63
}
64
}
65
66