metrale_grammar/fsm/
union_find.rs1use ahash::AHashMap;
8
9#[derive(Debug, Default)]
14pub struct UnionFindSet {
15 parent_size: AHashMap<i32, (i32, usize)>,
17}
18
19impl UnionFindSet {
20 pub fn new() -> Self {
22 Self {
23 parent_size: AHashMap::new(),
24 }
25 }
26
27 pub fn add(&mut self, element: i32) -> bool {
30 if self.parent_size.contains_key(&element) {
31 return false;
32 }
33 self.parent_size.insert(element, (element, 1));
34 true
35 }
36
37 pub fn clear(&mut self) {
39 self.parent_size.clear();
40 }
41
42 pub fn contains(&self, element: i32) -> bool {
44 self.parent_size.contains_key(&element)
45 }
46
47 pub fn find(&mut self, element: i32) -> i32 {
50 let parent = self
51 .parent_size
52 .get(&element)
53 .expect("Element not found in union-find set.")
54 .0;
55 if parent != element {
56 let root = self.find(parent);
57 self.parent_size.get_mut(&element).unwrap().0 = root;
58 root
59 } else {
60 element
61 }
62 }
63
64 pub fn union(&mut self, a: i32, b: i32) {
66 let mut root_a = self.find(a);
67 let mut root_b = self.find(b);
68 if root_a == root_b {
69 return;
70 }
71 let size_a = self.parent_size[&root_a].1;
72 let size_b = self.parent_size[&root_b].1;
73 if size_a < size_b {
75 std::mem::swap(&mut root_a, &mut root_b);
76 }
77 self.parent_size.get_mut(&root_b).unwrap().0 = root_a;
78 let merged = self.parent_size[&root_a].1 + self.parent_size[&root_b].1;
79 self.parent_size.get_mut(&root_a).unwrap().1 = merged;
80 }
81
82 pub fn all_sets(&mut self) -> Vec<Vec<i32>> {
85 let elements: Vec<i32> = self.parent_size.keys().copied().collect();
86 let mut root_to_idx: AHashMap<i32, usize> = AHashMap::new();
87 let mut result: Vec<Vec<i32>> = Vec::new();
88 for value in elements {
89 let root = self.find(value);
90 let idx = *root_to_idx.entry(root).or_insert_with(|| {
91 result.push(Vec::new());
92 result.len() - 1
93 });
94 result[idx].push(value);
95 }
96 for vec in &mut result {
97 vec.sort_unstable();
98 }
99 result.sort_by(|v1, v2| v1[0].cmp(&v2[0]));
100 result
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn add_is_idempotent() {
110 let mut uf = UnionFindSet::new();
111 assert!(uf.add(1));
112 assert!(!uf.add(1));
113 assert!(uf.contains(1));
114 assert!(!uf.contains(2));
115 }
116
117 #[test]
118 fn union_merges_sets() {
119 let mut uf = UnionFindSet::new();
120 for i in 0..4 {
121 uf.add(i);
122 }
123 uf.union(0, 1);
124 uf.union(2, 3);
125 assert_eq!(uf.find(0), uf.find(1));
126 assert_eq!(uf.find(2), uf.find(3));
127 assert_ne!(uf.find(0), uf.find(2));
128 uf.union(1, 2);
129 assert_eq!(uf.find(0), uf.find(3));
130 }
131
132 #[test]
133 fn all_sets_deterministic() {
134 let mut uf = UnionFindSet::new();
135 for i in 0..6 {
136 uf.add(i);
137 }
138 uf.union(4, 1);
139 uf.union(5, 2);
140 let sets = uf.all_sets();
141 assert_eq!(sets, vec![vec![0], vec![1, 4], vec![2, 5], vec![3]]);
143 }
144
145 #[test]
146 fn clear_empties() {
147 let mut uf = UnionFindSet::new();
148 uf.add(7);
149 uf.clear();
150 assert!(!uf.contains(7));
151 }
152
153 #[test]
154 #[should_panic(expected = "not found")]
155 fn find_missing_panics() {
156 let mut uf = UnionFindSet::new();
157 uf.find(99);
158 }
159}