Skip to content

Commit 2ffccb7

Browse files
committed
auto merge of #15857 : treeman/rust/doc-dijkstra-example, r=alexcrichton
I wanted to have a slightly larger example compared to the method examples, but I'm unsure how it worked out. Feedback would nice.
2 parents 5d3aaa8 + 94500b8 commit 2ffccb7

File tree

1 file changed

+137
-1
lines changed

1 file changed

+137
-1
lines changed

src/libcollections/priority_queue.rs

+137-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,143 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! A priority queue implemented with a binary heap
11+
//! A priority queue implemented with a binary heap.
12+
//!
13+
//! # Example
14+
//!
15+
//! This is a larger example which implements [Dijkstra's algorithm][dijkstra]
16+
//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
17+
//! It showcases how to use the `PriorityQueue` with custom types.
18+
//!
19+
//! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
20+
//! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem
21+
//! [dir_graph]: http://en.wikipedia.org/wiki/Directed_graph
22+
//!
23+
//! ```
24+
//! use std::collections::PriorityQueue;
25+
//! use std::uint;
26+
//!
27+
//! #[deriving(Eq, PartialEq)]
28+
//! struct State {
29+
//! cost: uint,
30+
//! position: uint
31+
//! }
32+
//!
33+
//! // The priority queue depends on `Ord`.
34+
//! // Explicitly implement the trait so the queue becomes a min-heap
35+
//! // instead of a max-heap.
36+
//! impl Ord for State {
37+
//! fn cmp(&self, other: &State) -> Ordering {
38+
//! // Notice that the we flip the ordering here
39+
//! other.cost.cmp(&self.cost)
40+
//! }
41+
//! }
42+
//!
43+
//! // `PartialOrd` needs to be implemented as well.
44+
//! impl PartialOrd for State {
45+
//! fn partial_cmp(&self, other: &State) -> Option<Ordering> {
46+
//! Some(self.cmp(other))
47+
//! }
48+
//! }
49+
//!
50+
//! // Each node is represented as an `uint`, for a shorter implementation.
51+
//! struct Edge {
52+
//! node: uint,
53+
//! cost: uint
54+
//! }
55+
//!
56+
//! // Dijkstra's shortest path algorithm.
57+
//!
58+
//! // Start at `start` and use `dist` to track the current shortest distance
59+
//! // to each node. This implementation isn't memory efficient as it may leave duplicate
60+
//! // nodes in the queue. It also uses `uint::MAX` as a sentinel value,
61+
//! // for a simpler implementation.
62+
//! fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: uint, goal: uint) -> uint {
63+
//! // dist[node] = current shortest distance from `start` to `node`
64+
//! let mut dist = Vec::from_elem(adj_list.len(), uint::MAX);
65+
//!
66+
//! let mut pq = PriorityQueue::new();
67+
//!
68+
//! // We're at `start`, with a zero cost
69+
//! *dist.get_mut(start) = 0u;
70+
//! pq.push(State { cost: 0u, position: start });
71+
//!
72+
//! // Examine the frontier with lower cost nodes first (min-heap)
73+
//! loop {
74+
//! let State { cost, position } = match pq.pop() {
75+
//! None => break, // empty
76+
//! Some(s) => s
77+
//! };
78+
//!
79+
//! // Alternatively we could have continued to find all shortest paths
80+
//! if position == goal { return cost }
81+
//!
82+
//! // Important as we may have already found a better way
83+
//! if cost > dist[position] { continue }
84+
//!
85+
//! // For each node we can reach, see if we can find a way with
86+
//! // a lower cost going through this node
87+
//! for edge in adj_list[position].iter() {
88+
//! let next = State { cost: cost + edge.cost, position: edge.node };
89+
//!
90+
//! // If so, add it to the frontier and continue
91+
//! if next.cost < dist[next.position] {
92+
//! pq.push(next);
93+
//! // Relaxation, we have now found a better way
94+
//! *dist.get_mut(next.position) = next.cost;
95+
//! }
96+
//! }
97+
//! }
98+
//!
99+
//! // Goal not reachable
100+
//! uint::MAX
101+
//! }
102+
//!
103+
//! fn main() {
104+
//! // This is the directed graph we're going to use.
105+
//! // The node numbers correspond to the different states,
106+
//! // and the edge weights symbolises the cost of moving
107+
//! // from one node to another.
108+
//! // Note that the edges are one-way.
109+
//! //
110+
//! // 7
111+
//! // +-----------------+
112+
//! // | |
113+
//! // v 1 2 |
114+
//! // 0 -----> 1 -----> 3 ---> 4
115+
//! // | ^ ^ ^
116+
//! // | | 1 | |
117+
//! // | | | 3 | 1
118+
//! // +------> 2 -------+ |
119+
//! // 10 | |
120+
//! // +---------------+
121+
//! //
122+
//! // The graph is represented as an adjecency list where each index,
123+
//! // corresponding to a node value, has a list of outgoing edges.
124+
//! // Chosen for it's efficiency.
125+
//! let graph = vec![
126+
//! // Node 0
127+
//! vec![Edge { node: 2, cost: 10 },
128+
//! Edge { node: 1, cost: 1 }],
129+
//! // Node 1
130+
//! vec![Edge { node: 3, cost: 2 }],
131+
//! // Node 2
132+
//! vec![Edge { node: 1, cost: 1 },
133+
//! Edge { node: 3, cost: 3 },
134+
//! Edge { node: 4, cost: 1 }],
135+
//! // Node 3
136+
//! vec![Edge { node: 0, cost: 7 },
137+
//! Edge { node: 4, cost: 2 }],
138+
//! // Node 4
139+
//! vec![]];
140+
//!
141+
//! assert_eq!(shortest_path(&graph, 0, 1), 1);
142+
//! assert_eq!(shortest_path(&graph, 0, 3), 3);
143+
//! assert_eq!(shortest_path(&graph, 3, 0), 7);
144+
//! assert_eq!(shortest_path(&graph, 0, 4), 5);
145+
//! assert_eq!(shortest_path(&graph, 4, 0), uint::MAX);
146+
//! }
147+
//! ```
12148
13149
#![allow(missing_doc)]
14150

0 commit comments

Comments
 (0)