Skip to content

Commit

Permalink
Fixed dijkstra implementation bug: improved time from exponential to …
Browse files Browse the repository at this point in the history
…O(E * logV) (#848)

Fixed dijkstra implementation: the previous implementation incorrectly prioritized unvisited nodes with the smallest vertex instead of the smallest weight.
  • Loading branch information
taaae authored Dec 26, 2024
1 parent 7903120 commit 8467b52
Showing 1 changed file with 11 additions and 7 deletions.
18 changes: 11 additions & 7 deletions src/graph/dijkstra.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};
use std::ops::Add;

type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;

// performs Dijsktra's algorithm on the given graph from the given start
// the graph is a positively-weighted undirected graph
// the graph is a positively-weighted directed graph
//
// returns a map that for each reachable vertex associates the distance and the predecessor
// since the start has no predecessor but is reachable, map[start] will be None
Expand All @@ -17,17 +17,17 @@ pub fn dijkstra<V: Ord + Copy, E: Ord + Copy + Add<Output = E>>(
start: V,
) -> BTreeMap<V, Option<(V, E)>> {
let mut ans = BTreeMap::new();
let mut prio = BTreeMap::new();
let mut prio = BTreeSet::new();

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

for (new, weight) in &graph[&start] {
ans.insert(*new, Some((start, *weight)));
prio.insert(*new, *weight);
prio.insert((*weight, *new));
}

while let Some((vertex, path_weight)) = prio.pop_first() {
while let Some((path_weight, vertex)) = prio.pop_first() {
for (next, weight) in &graph[&vertex] {
let new_weight = path_weight + *weight;
match ans.get(next) {
Expand All @@ -37,8 +37,12 @@ pub fn dijkstra<V: Ord + Copy, E: Ord + Copy + Add<Output = E>>(
Some(None) => {}
// the new path is shorter, either new was not in ans or it was farther
_ => {
ans.insert(*next, Some((vertex, new_weight)));
prio.insert(*next, new_weight);
if let Some(Some((_, prev_weight))) =
ans.insert(*next, Some((vertex, new_weight)))
{
prio.remove(&(prev_weight, *next));
}
prio.insert((new_weight, *next));
}
}
}
Expand Down

0 comments on commit 8467b52

Please sign in to comment.