1
- use std:: cmp:: Reverse ;
2
- use std:: collections:: { BTreeMap , BinaryHeap } ;
1
+ use std:: collections:: BTreeMap ;
3
2
use std:: ops:: Add ;
4
3
5
4
type Graph < V , E > = BTreeMap < V , BTreeMap < V , E > > ;
@@ -9,39 +8,37 @@ type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;
9
8
//
10
9
// returns a map that for each reachable vertex associates the distance and the predecessor
11
10
// since the start has no predecessor but is reachable, map[start] will be None
11
+ //
12
+ // Time: O(E * logV). For each vertex, we traverse each edge, resulting in O(E). For each edge, we
13
+ // insert a new shortest path for a vertex into the tree, resulting in O(E * logV).
14
+ // Space: O(V). The tree holds up to V vertices.
12
15
pub fn dijkstra < V : Ord + Copy , E : Ord + Copy + Add < Output = E > > (
13
16
graph : & Graph < V , E > ,
14
17
start : V ,
15
18
) -> BTreeMap < V , Option < ( V , E ) > > {
16
19
let mut ans = BTreeMap :: new ( ) ;
17
- let mut prio = BinaryHeap :: new ( ) ;
20
+ let mut prio = BTreeMap :: new ( ) ;
18
21
19
22
// start is the special case that doesn't have a predecessor
20
23
ans. insert ( start, None ) ;
21
24
22
25
for ( new, weight) in & graph[ & start] {
23
26
ans. insert ( * new, Some ( ( start, * weight) ) ) ;
24
- prio. push ( Reverse ( ( * weight , * new, start ) ) ) ;
27
+ prio. insert ( * new, * weight ) ;
25
28
}
26
29
27
- while let Some ( Reverse ( ( dist_new, new, prev) ) ) = prio. pop ( ) {
28
- match ans[ & new] {
29
- // what we popped is what is in ans, we'll compute it
30
- Some ( ( p, d) ) if p == prev && d == dist_new => { }
31
- // otherwise it's not interesting
32
- _ => continue ,
33
- }
34
-
35
- for ( next, weight) in & graph[ & new] {
30
+ while let Some ( ( vertex, path_weight) ) = prio. pop_first ( ) {
31
+ for ( next, weight) in & graph[ & vertex] {
32
+ let new_weight = path_weight + * weight;
36
33
match ans. get ( next) {
37
34
// if ans[next] is a lower dist than the alternative one, we do nothing
38
- Some ( Some ( ( _, dist_next) ) ) if dist_new + * weight >= * dist_next => { }
35
+ Some ( Some ( ( _, dist_next) ) ) if new_weight >= * dist_next => { }
39
36
// if ans[next] is None then next is start and so the distance won't be changed, it won't be added again in prio
40
37
Some ( None ) => { }
41
38
// the new path is shorter, either new was not in ans or it was farther
42
39
_ => {
43
- ans. insert ( * next, Some ( ( new , * weight + dist_new ) ) ) ;
44
- prio. push ( Reverse ( ( * weight + dist_new , * next, new ) ) ) ;
40
+ ans. insert ( * next, Some ( ( vertex , new_weight ) ) ) ;
41
+ prio. insert ( * next, new_weight ) ;
45
42
}
46
43
}
47
44
}
0 commit comments