Skip to content

Commit 12258ed

Browse files
authored
Decrease Dijkstra upper bound from O(ElogE) to O(ElogV) (TheAlgorithms#636)
1 parent f7f2769 commit 12258ed

File tree

1 file changed

+13
-16
lines changed

1 file changed

+13
-16
lines changed

src/graph/dijkstra.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use std::cmp::Reverse;
2-
use std::collections::{BTreeMap, BinaryHeap};
1+
use std::collections::BTreeMap;
32
use std::ops::Add;
43

54
type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;
@@ -9,39 +8,37 @@ type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;
98
//
109
// returns a map that for each reachable vertex associates the distance and the predecessor
1110
// 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.
1215
pub fn dijkstra<V: Ord + Copy, E: Ord + Copy + Add<Output = E>>(
1316
graph: &Graph<V, E>,
1417
start: V,
1518
) -> BTreeMap<V, Option<(V, E)>> {
1619
let mut ans = BTreeMap::new();
17-
let mut prio = BinaryHeap::new();
20+
let mut prio = BTreeMap::new();
1821

1922
// start is the special case that doesn't have a predecessor
2023
ans.insert(start, None);
2124

2225
for (new, weight) in &graph[&start] {
2326
ans.insert(*new, Some((start, *weight)));
24-
prio.push(Reverse((*weight, *new, start)));
27+
prio.insert(*new, *weight);
2528
}
2629

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;
3633
match ans.get(next) {
3734
// 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 => {}
3936
// 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
4037
Some(None) => {}
4138
// the new path is shorter, either new was not in ans or it was farther
4239
_ => {
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);
4542
}
4643
}
4744
}

0 commit comments

Comments
 (0)