# Dijkstra's Algorithm

For rust, I’m updating the documentation for the standard library and specifically with the collections. For the priority queue I had the idea to use Dijkstra’s algorithm as a fun example. That idea was well received and that example is now live.

At first I wanted to use A* to solve the eight puzzle, which I’ve done before, but that example became far too big.

Here’s the example code currently up in docs:

Using `rustc 0.12.0-pre (ef352faea84fa16616b773bd9aa5020d7c76bff0 2014-07-18 21:46:32 +0000`)

``````use std::collections::PriorityQueue;
use std::uint;

#[deriving(Eq, PartialEq)]
struct State {
cost: uint,
position: uint
}

// The priority queue depends on `Ord`.
// Explicitly implement the trait so the queue becomes a min-heap
// instead of a max-heap.
impl Ord for State {
fn cmp(&self, other: &State) -> Ordering {
// Notice that the we flip the ordering here
other.cost.cmp(&self.cost)
}
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for State {
fn partial_cmp(&self, other: &State) -> Option<Ordering> {
Some(self.cmp(other))
}
}

// Each node is represented as an `uint`, for a shorter implementation.
struct Edge {
node: uint,
cost: uint
}

// Dijkstra's shortest path algorithm.

// Start at `start` and use `dist` to track the current shortest distance
// to each node. This implementation isn't memory efficient as it may leave duplicate
// nodes in the queue. It also uses `uint::MAX` as a sentinel value,
// for a simpler implementation.
fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: uint, goal: uint) -> uint {
// dist[node] = current shortest distance from `start` to `node`
let mut dist = Vec::from_elem(adj_list.len(), uint::MAX);

let mut pq = PriorityQueue::new();

// We're at `start`, with a zero cost
*dist.get_mut(start) = 0u;
pq.push(State { cost: 0u, position: start });

// Examine the frontier with lower cost nodes first (min-heap)
loop {
let State { cost, position } = match pq.pop() {
None => break, // empty
Some(s) => s
};

// Alternatively we could have continued to find all shortest paths
if position == goal { return cost }

// Important as we may have already found a better way
if cost > dist[position] { continue }

// For each node we can reach, see if we can find a way with
// a lower cost going through this node
for edge in adj_list[position].iter() {
let next = State { cost: cost + edge.cost, position: edge.node };

// If so, add it to the frontier and continue
if next.cost < dist[next.position] {
pq.push(next);
// Relaxation, we have now found a better way
*dist.get_mut(next.position) = next.cost;
}
}
}

// Goal not reachable
uint::MAX
}

fn main() {
// This is the directed graph we're going to use.
// The node numbers correspond to the different states,
// and the edge weights symbolises the cost of moving
// from one node to another.
// Note that the edges are one-way.
//
//                  7
//          +-----------------+
//          |                 |
//          v   1        2    |
//          0 -----> 1 -----> 3 ---> 4
//          |        ^        ^      ^
//          |        | 1      |      |
//          |        |        | 3    | 1
//          +------> 2 -------+      |
//           10      |               |
//                   +---------------+
//
// The graph is represented as an adjecency list where each index,
// corresponding to a node value, has a list of outgoing edges.
// Chosen for it's efficiency.
let graph = vec![
// Node 0
vec![Edge { node: 2, cost: 10 },
Edge { node: 1, cost: 1 }],
// Node 1
vec![Edge { node: 3, cost: 2 }],
// Node 2
vec![Edge { node: 1, cost: 1 },
Edge { node: 3, cost: 3 },
Edge { node: 4, cost: 1 }],
// Node 3
vec![Edge { node: 0, cost: 7 },
Edge { node: 4, cost: 2 }],
// Node 4
vec![]];

assert_eq!(shortest_path(&graph, 0, 1), 1);
assert_eq!(shortest_path(&graph, 0, 3), 3);
assert_eq!(shortest_path(&graph, 3, 0), 7);
assert_eq!(shortest_path(&graph, 0, 4), 5);
assert_eq!(shortest_path(&graph, 4, 0), uint::MAX);
}``````