Dijkstra’s Algorithm

Dijkstra’s single-source shortest path on a weighted graph.

Given a directed or undirected graph with non-negative edge weights, Dijkstra’s algorithm computes the shortest distance from a source vertex to every other reachable vertex in O((V + E) log V) time using a binary heap.

The Rust crate lives at dijkstra/src/lib.rs; build & run it with:

$ cd dijkstra && cargo run
$ cd dijkstra && cargo test

Generated API reference for the Dijkstra crate. View the rendered API reference →

 1//! Dijkstra's single-source shortest path on a weighted graph.
 2//!
 3//! Given a directed or undirected graph with non-negative edge weights,
 4//! Dijkstra's algorithm computes the shortest distance from a source
 5//! vertex to every other reachable vertex in `O((V + E) log V)` time
 6//! using a binary heap.
 7//!
 8//! This module exposes a single function [`dijkstra`] that takes the
 9//! adjacency list as `&[Vec<(usize, u64)>]` (each edge is `(neighbor,
10//! weight)`) and returns a `HashMap<usize, u64>` of minimum distances.
11
12use std::cmp::Reverse;
13use std::collections::{BinaryHeap, HashMap};
14
15/// Compute shortest distances from `source` to every reachable vertex.
16///
17/// `graph[u]` is the list of edges leaving `u`: pairs `(v, w)` meaning
18/// there is an edge to `v` with weight `w`. Returns a map from vertex
19/// id to minimum distance. Unreachable vertices are absent.
20///
21/// # Panics
22///
23/// Panics if `source >= graph.len()`.
24pub fn dijkstra(graph: &[Vec<(usize, u64)>], source: usize) -> HashMap<usize, u64> {
25    assert!(source < graph.len(), "source vertex out of range");
26    let mut dist: HashMap<usize, u64> = HashMap::new();
27    let mut heap: BinaryHeap<Reverse<(u64, usize)>> = BinaryHeap::new();
28    dist.insert(source, 0);
29    heap.push(Reverse((0, source)));
30    while let Some(Reverse((d, u))) = heap.pop() {
31        if d > dist[&u] {
32            continue; // stale entry
33        }
34        for &(v, w) in &graph[u] {
35            let nd = d + w;
36            let is_better = match dist.get(&v) {
37                None => true,
38                Some(cur) => nd < *cur,
39            };
40            if is_better {
41                dist.insert(v, nd);
42                heap.push(Reverse((nd, v)));
43            }
44        }
45    }
46    dist
47}