Skip to content

Commit fb2725b

Browse files
committed
feat: add a tree center algorithm implementation
1 parent 8856177 commit fb2725b

2 files changed

Lines changed: 287 additions & 0 deletions

File tree

src/graph/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod prufer_code;
2525
mod strongly_connected_components;
2626
mod tarjans_ssc;
2727
mod topological_sort;
28+
mod tree_center;
2829
mod two_satisfiability;
2930

3031
pub use self::ant_colony_optimization::ant_colony_optimization;
@@ -54,4 +55,5 @@ pub use self::prufer_code::{prufer_decode, prufer_encode};
5455
pub use self::strongly_connected_components::StronglyConnectedComponents;
5556
pub use self::tarjans_ssc::tarjan_scc;
5657
pub use self::topological_sort::topological_sort;
58+
pub use self::tree_center::tree_center;
5759
pub use self::two_satisfiability::solve_two_satisfiability;

src/graph/tree_center.rs

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
use std::collections::HashMap;
2+
3+
use crate::data_structures::{graph::Graph, UndirectedGraph};
4+
5+
type Table<V> = HashMap<V, i64>;
6+
7+
const INF: i64 = 1_000_000_000_000_000_000;
8+
9+
fn depth_first_search_down<'a>(
10+
tree: &'a UndirectedGraph,
11+
dist: &mut Table<&'a String>,
12+
max_down: &mut Table<&'a String>,
13+
u: &'a String,
14+
parent: Option<&'a String>,
15+
) {
16+
let dist_from_root = *dist.get(u).unwrap();
17+
18+
let mut max_dist_down = dist_from_root;
19+
20+
for (v, weight) in tree.adjacency_table().get(u).unwrap() {
21+
if parent == Some(v) {
22+
continue;
23+
}
24+
25+
dist.insert(v, dist_from_root + *weight as i64);
26+
27+
depth_first_search_down(tree, dist, max_down, v, Some(u));
28+
29+
max_dist_down = max_dist_down.max(*max_down.get(v).unwrap());
30+
}
31+
32+
max_down.insert(u, max_dist_down);
33+
}
34+
35+
fn depth_first_search_up<'a>(
36+
tree: &'a UndirectedGraph,
37+
dist: &mut Table<&'a String>,
38+
max_dist: &mut Table<&'a String>,
39+
max_down: &mut Table<&'a String>,
40+
u: &'a String,
41+
parent: Option<&'a String>,
42+
mut max_up: i64,
43+
) {
44+
let mut first_max_down = -INF;
45+
let mut second_max_down = -INF;
46+
47+
for (v, _) in tree.adjacency_table().get(u).unwrap() {
48+
if parent == Some(v) {
49+
continue;
50+
}
51+
52+
let dist_max_down = *max_down.get(v).unwrap();
53+
54+
if first_max_down < dist_max_down {
55+
second_max_down = first_max_down;
56+
first_max_down = dist_max_down;
57+
} else {
58+
second_max_down = second_max_down.max(dist_max_down);
59+
}
60+
}
61+
62+
let dist_from_root = *dist.get(u).unwrap();
63+
64+
max_up = max_up.max(0);
65+
66+
max_dist.insert(u, max_up.max(*max_down.get(u).unwrap() - dist_from_root));
67+
68+
for (v, weight) in tree.adjacency_table().get(u).unwrap() {
69+
if parent == Some(v) {
70+
continue;
71+
}
72+
73+
let dist_max_down = *max_down.get(v).unwrap();
74+
75+
let mut max_dist_up = if first_max_down == dist_max_down {
76+
second_max_down
77+
} else {
78+
first_max_down
79+
};
80+
81+
max_dist_up = max_up.max(max_dist_up - dist_from_root) + *weight as i64;
82+
83+
depth_first_search_up(tree, dist, max_dist, max_down, v, Some(u), max_dist_up);
84+
}
85+
}
86+
87+
pub fn tree_center(tree: &UndirectedGraph) -> Option<Vec<String>> {
88+
let node = tree.adjacency_table().keys().last();
89+
90+
if Option::is_none(&node) {
91+
return None;
92+
}
93+
94+
let mut dist = Table::new();
95+
96+
let mut max_dist = Table::new();
97+
98+
let mut max_down = Table::new();
99+
100+
let root = node.unwrap();
101+
102+
dist.insert(root, 0);
103+
104+
depth_first_search_down(tree, &mut dist, &mut max_down, root, None);
105+
106+
depth_first_search_up(
107+
tree,
108+
&mut dist,
109+
&mut max_dist,
110+
&mut max_down,
111+
root,
112+
None,
113+
-INF,
114+
);
115+
116+
let min_dist = max_dist.iter().map(|v| *v.1).min().unwrap();
117+
118+
let center = max_dist
119+
.iter()
120+
.filter(|v| *v.1 == min_dist)
121+
.map(|v| (*v.0).clone())
122+
.collect::<Vec<_>>();
123+
124+
Some(center)
125+
}
126+
127+
#[cfg(test)]
128+
mod tests {
129+
use super::*;
130+
131+
#[test]
132+
fn test_empty_graph() {
133+
let tree = UndirectedGraph::new();
134+
135+
let center = tree_center(&tree);
136+
137+
assert_eq!(center, None);
138+
}
139+
140+
#[test]
141+
fn test_trivial_graph() {
142+
let mut tree = UndirectedGraph::new();
143+
let expected = vec!["0".to_string()];
144+
145+
tree.add_node("0");
146+
147+
let center = tree_center(&tree).unwrap();
148+
149+
assert_eq!(center, expected);
150+
}
151+
152+
#[test]
153+
fn test_edge() {
154+
let mut tree = UndirectedGraph::new();
155+
let expected = vec!["0".to_string(), "1".to_string()];
156+
157+
tree.add_edge(("0", "1", 1));
158+
159+
let mut center = tree_center(&tree).unwrap();
160+
161+
center.sort();
162+
163+
assert_eq!(center, expected);
164+
}
165+
166+
#[test]
167+
fn test_simple_path() {
168+
let mut tree = UndirectedGraph::new();
169+
let expected = vec!["2".to_string(), "3".to_string()];
170+
171+
tree.add_edge(("0", "1", 1));
172+
tree.add_edge(("1", "2", 1));
173+
tree.add_edge(("2", "3", 1));
174+
tree.add_edge(("3", "4", 1));
175+
tree.add_edge(("4", "5", 1));
176+
177+
let mut center = tree_center(&tree).unwrap();
178+
179+
center.sort();
180+
181+
assert_eq!(center, expected);
182+
}
183+
184+
#[test]
185+
fn test_star_tree() {
186+
let mut tree = UndirectedGraph::new();
187+
let expected = vec!["0".to_string()];
188+
189+
tree.add_edge(("0", "1", 1));
190+
tree.add_edge(("0", "2", 1));
191+
tree.add_edge(("0", "3", 1));
192+
tree.add_edge(("0", "4", 1));
193+
194+
let center = tree_center(&tree).unwrap();
195+
196+
assert_eq!(center, expected);
197+
}
198+
199+
#[test]
200+
fn test_bi_star_tree() {
201+
let mut tree = UndirectedGraph::new();
202+
let expected = vec!["0".to_string(), "1".to_string()];
203+
204+
tree.add_edge(("0", "2", 1));
205+
tree.add_edge(("0", "3", 1));
206+
tree.add_edge(("0", "4", 1));
207+
tree.add_edge(("1", "5", 1));
208+
tree.add_edge(("1", "6", 1));
209+
tree.add_edge(("1", "7", 1));
210+
tree.add_edge(("0", "1", 1));
211+
212+
let mut center = tree_center(&tree).unwrap();
213+
214+
center.sort();
215+
216+
assert_eq!(center, expected);
217+
}
218+
219+
#[test]
220+
fn test_simple_path_10_vertices_tree() {
221+
let mut tree = UndirectedGraph::new();
222+
let expected = ["10".to_string(), "9".to_string()];
223+
224+
tree.add_edge(("4", "1", 1));
225+
tree.add_edge(("6", "5", 1));
226+
tree.add_edge(("7", "2", 1));
227+
tree.add_edge(("6", "3", 1));
228+
tree.add_edge(("1", "7", 1));
229+
tree.add_edge(("2", "10", 1));
230+
tree.add_edge(("10", "9", 1));
231+
tree.add_edge(("3", "8", 1));
232+
tree.add_edge(("8", "9", 1));
233+
234+
let mut center = tree_center(&tree).unwrap();
235+
236+
center.sort();
237+
238+
assert_eq!(center, expected);
239+
}
240+
241+
#[test]
242+
fn test_simple_weighted_path() {
243+
let mut tree = UndirectedGraph::new();
244+
let expected = vec!["2".to_string()];
245+
246+
tree.add_edge(("4", "2", 10));
247+
tree.add_edge(("2", "3", 5));
248+
tree.add_edge(("3", "1", 5));
249+
250+
let center = tree_center(&tree).unwrap();
251+
252+
assert_eq!(center, expected);
253+
}
254+
255+
#[test]
256+
fn test_bi_weighted_tree() {
257+
let mut tree = UndirectedGraph::new();
258+
let expected = vec!["1".to_string()];
259+
260+
tree.add_edge(("1", "2", 4));
261+
tree.add_edge(("1", "3", 4));
262+
tree.add_edge(("1", "4", 1));
263+
tree.add_edge(("4", "5", 1));
264+
265+
let center = tree_center(&tree).unwrap();
266+
267+
assert_eq!(center, expected);
268+
}
269+
270+
#[test]
271+
fn test_star_weighted_tree() {
272+
let mut tree = UndirectedGraph::new();
273+
let expected = vec!["1".to_string(), "2".to_string()];
274+
275+
tree.add_edge(("1", "2", 0));
276+
tree.add_edge(("1", "3", 2));
277+
tree.add_edge(("1", "4", 2));
278+
279+
let mut center = tree_center(&tree).unwrap();
280+
281+
center.sort();
282+
283+
assert_eq!(center, expected);
284+
}
285+
}

0 commit comments

Comments
 (0)