|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
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 |
| -//! ``` |
| 11 | +//! A priority queue implemented with a binary heap |
148 | 12 |
|
149 | 13 | #![allow(missing_doc)]
|
150 | 14 |
|
|
0 commit comments