advanced_algorithms/graph/
dijkstra.rs1use crate::graph::Graph;
25use std::collections::BinaryHeap;
26use std::cmp::Ordering;
27
28#[derive(Debug, Clone)]
30struct State {
31 node: usize,
32 distance: f64,
33}
34
35impl Eq for State {}
36
37impl PartialEq for State {
38 fn eq(&self, other: &Self) -> bool {
39 self.distance == other.distance && self.node == other.node
40 }
41}
42
43impl Ord for State {
44 fn cmp(&self, other: &Self) -> Ordering {
45 other.distance.partial_cmp(&self.distance)
47 .unwrap_or(Ordering::Equal)
48 .then_with(|| self.node.cmp(&other.node))
49 }
50}
51
52impl PartialOrd for State {
53 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
54 Some(self.cmp(other))
55 }
56}
57
58#[derive(Debug, Clone)]
60pub struct ShortestPathResult {
61 pub distance: Vec<f64>,
63 pub previous: Vec<Option<usize>>,
65 pub source: usize,
67}
68
69impl ShortestPathResult {
70 pub fn path_to(&self, target: usize) -> Option<Vec<usize>> {
72 if self.distance[target].is_infinite() {
73 return None;
74 }
75
76 let mut path = Vec::new();
77 let mut current = target;
78
79 while current != self.source {
80 path.push(current);
81 current = self.previous[current]?;
82 }
83
84 path.push(self.source);
85 path.reverse();
86
87 Some(path)
88 }
89}
90
91pub fn shortest_path(graph: &Graph, source: usize) -> ShortestPathResult {
106 let n = graph.n_nodes;
107
108 let mut distance = vec![f64::INFINITY; n];
109 let mut previous = vec![None; n];
110 let mut heap = BinaryHeap::new();
111
112 distance[source] = 0.0;
113 heap.push(State {
114 node: source,
115 distance: 0.0,
116 });
117
118 while let Some(State { node, distance: dist }) = heap.pop() {
119 if dist > distance[node] {
121 continue;
122 }
123
124 for &(neighbor, weight) in graph.neighbors(node) {
126 assert!(weight >= 0.0, "Dijkstra's algorithm requires non-negative weights");
127
128 let new_distance = dist + weight;
129
130 if new_distance < distance[neighbor] {
131 distance[neighbor] = new_distance;
132 previous[neighbor] = Some(node);
133
134 heap.push(State {
135 node: neighbor,
136 distance: new_distance,
137 });
138 }
139 }
140 }
141
142 ShortestPathResult {
143 distance,
144 previous,
145 source,
146 }
147}
148
149pub fn shortest_path_to_target(
153 graph: &Graph,
154 source: usize,
155 target: usize,
156) -> Option<(f64, Vec<usize>)> {
157 let n = graph.n_nodes;
158
159 let mut distance = vec![f64::INFINITY; n];
160 let mut previous = vec![None; n];
161 let mut heap = BinaryHeap::new();
162
163 distance[source] = 0.0;
164 heap.push(State {
165 node: source,
166 distance: 0.0,
167 });
168
169 while let Some(State { node, distance: dist }) = heap.pop() {
170 if node == target {
172 let result = ShortestPathResult {
173 distance,
174 previous,
175 source,
176 };
177
178 return Some((dist, result.path_to(target)?));
179 }
180
181 if dist > distance[node] {
182 continue;
183 }
184
185 for &(neighbor, weight) in graph.neighbors(node) {
186 let new_distance = dist + weight;
187
188 if new_distance < distance[neighbor] {
189 distance[neighbor] = new_distance;
190 previous[neighbor] = Some(node);
191
192 heap.push(State {
193 node: neighbor,
194 distance: new_distance,
195 });
196 }
197 }
198 }
199
200 None
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_simple_path() {
209 let mut graph = Graph::new(4);
210 graph.add_edge(0, 1, 1.0);
211 graph.add_edge(1, 2, 2.0);
212 graph.add_edge(2, 3, 3.0);
213 graph.add_edge(0, 3, 10.0);
214
215 let result = shortest_path(&graph, 0);
216
217 assert_eq!(result.distance[3], 6.0);
218
219 let path = result.path_to(3).unwrap();
220 assert_eq!(path, vec![0, 1, 2, 3]);
221 }
222
223 #[test]
224 fn test_multiple_paths() {
225 let mut graph = Graph::new(5);
226 graph.add_edge(0, 1, 4.0);
227 graph.add_edge(0, 2, 1.0);
228 graph.add_edge(2, 1, 2.0);
229 graph.add_edge(1, 3, 1.0);
230 graph.add_edge(2, 3, 5.0);
231 graph.add_edge(3, 4, 1.0);
232
233 let result = shortest_path(&graph, 0);
234
235 assert_eq!(result.distance[1], 3.0); assert_eq!(result.distance[3], 4.0); assert_eq!(result.distance[4], 5.0);
238 }
239
240 #[test]
241 fn test_disconnected() {
242 let mut graph = Graph::new(3);
243 graph.add_edge(0, 1, 1.0);
244
245 let result = shortest_path(&graph, 0);
246
247 assert!(result.distance[2].is_infinite());
248 assert!(result.path_to(2).is_none());
249 }
250}