1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use std::collections::{
HashMap,
BinaryHeap,
};
use std::collections::hash_map::Entry::{
Occupied,
Vacant,
};
use std::hash::Hash;
use scored::MinScored;
use super::visit::{
Visitable,
VisitMap,
IntoEdges,
EdgeRef,
};
use algo::Measure;
pub fn dijkstra<G, F, K>(graph: G, start: G::NodeId, goal: Option<G::NodeId>,
mut edge_cost: F)
-> HashMap<G::NodeId, K>
where G: IntoEdges + Visitable,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: Measure + Copy,
{
let mut visited = graph.visit_map();
let mut scores = HashMap::new();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
scores.insert(start, zero_score);
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
if visited.is_visited(&node) {
continue
}
if goal.as_ref() == Some(&node) {
break
}
for edge in graph.edges(node) {
let next = edge.target();
if visited.is_visited(&next) {
continue
}
let mut next_score = node_score + edge_cost(edge);
match scores.entry(next) {
Occupied(ent) => if next_score < *ent.get() {
*ent.into_mut() = next_score;
} else {
next_score = *ent.get();
},
Vacant(ent) => {
ent.insert(next_score);
}
}
visit_next.push(MinScored(next_score, next));
}
visited.visit(node);
}
scores
}