algorithms_edu/algo/graph/
topological_sort.rs1use crate::algo::graph::{Edge, WeightedAdjacencyList};
17use partial_min_max::min;
18
19impl WeightedAdjacencyList {
20 pub fn toposort(&self) -> Vec<usize> {
21 let n = self.node_count();
22 let mut visited = vec![false; n];
23 let mut ordering = vec![0usize; n];
24 let mut i = n - 1;
25
26 fn _dfs(
27 mut i: usize,
28 at: usize,
29 visited: &mut [bool],
30 ordering: &mut [usize],
31 graph: &WeightedAdjacencyList,
32 ) -> usize {
33 visited[at] = true;
34 for &edge in &graph[at] {
35 if !visited[edge.to] {
36 i = _dfs(i, edge.to, visited, ordering, graph);
37 }
38 }
39 ordering[i] = at;
40 i.saturating_sub(1)
41 }
42
43 for at in 0..n {
44 if !visited[at] {
45 i = _dfs(i, at, &mut visited, &mut ordering, &self);
46 }
47 }
48
49 ordering
50 }
51 pub fn toposort_khan(&self) -> Vec<usize> {
53 let n = self.node_count();
54 let mut dependencies = vec![0; n];
56 for (_dependency, dependent, _cost) in self.edges() {
58 dependencies[dependent] += 1;
59 }
60 let mut buildables: Vec<_> = (0..n).filter(|&i| dependencies[i] == 0).collect();
62 let mut i = 0;
63 let mut ordering = vec![0; n];
66 while i < n {
67 let mut new_buildables = Vec::new();
68 for &buildable in &buildables {
69 ordering[i] = buildable;
70 i += 1;
71 for &dependent in &self[buildable] {
72 let x = &mut dependencies[dependent.to];
73 *x -= 1;
74 if *x == 0 {
75 new_buildables.push(dependent.to);
76 }
77 }
78 }
79 buildables = new_buildables;
80 }
81 ordering
82 }
83 pub fn dag_shortest_path(&self, start: usize) -> Vec<f64> {
84 let toposort = self.toposort_khan();
85 let mut dists = vec![f64::INFINITY; self.node_count()];
86 dists[start] = 0.;
87 let i = toposort
88 .iter()
89 .position(|&node_id| node_id == start)
90 .unwrap();
91 toposort.into_iter().skip(i).for_each(|node_id| {
92 let cur_dist = dists[node_id];
93 if cur_dist.is_finite() {
94 for &Edge { to, weight } in &self[node_id] {
95 let new_dist = cur_dist + weight;
96 let dist = &mut dists[to];
97 *dist = min(*dist, new_dist);
98 }
99 }
100 });
101 dists
102 }
103}
104
105#[cfg(test)]
106mod tests {
107
108 use super::*;
109 #[test]
110 fn test_toposort() {
111 let edges = [
114 [0, 2],
115 [3, 1],
116 [1, 4],
117 [4, 5],
118 [3, 4],
119 [2, 6],
120 [6, 7],
121 [4, 8],
122 [9, 2],
123 [9, 10],
124 [10, 6],
125 [6, 11],
126 [11, 12],
127 [12, 8],
128 [7, 12],
129 [0, 6],
130 ];
131 let graph = WeightedAdjacencyList::new_directed_unweighted(13, &edges);
132 let ordering = graph.toposort_khan();
133 assert!(check_sort_result(&ordering, &edges));
134 let ordering = graph.toposort();
135 assert!(check_sort_result(&ordering, &edges));
136
137 fn check_sort_result(result: &[usize], edges: &[[usize; 2]]) -> bool {
138 let mut rank = vec![0; result.len()];
139 for (i, &node) in result.iter().enumerate() {
140 rank[node] = i;
141 }
142 edges
143 .iter()
144 .all(|&[dependency, dependent]| rank[dependency] < rank[dependent])
145 }
146 }
147 #[test]
148 fn test_dag_shortest_path() {
149 let edges = &[
150 (0, 1, 3.),
151 (0, 2, 2.),
152 (0, 5, 3.),
153 (1, 3, 1.),
154 (1, 2, 6.),
155 (2, 3, 1.),
156 (2, 4, 10.),
157 (3, 4, 5.),
158 (5, 4, 7.),
159 ];
160 let graph = WeightedAdjacencyList::new_directed(7, edges);
161 let dists = graph.dag_shortest_path(0);
162 assert_eq!(&dists, &[0., 3., 2., 3., 8., 3., f64::INFINITY])
163 }
164}