reddb_server/storage/engine/algorithms/
components.rs1use std::collections::HashMap;
7
8use super::super::graph_store::GraphStore;
9
10pub(crate) struct UnionFind {
16 parent: HashMap<String, String>,
17 rank: HashMap<String, usize>,
18}
19
20impl UnionFind {
21 pub fn new() -> Self {
22 Self {
23 parent: HashMap::new(),
24 rank: HashMap::new(),
25 }
26 }
27
28 pub fn make_set(&mut self, x: &str) {
29 if !self.parent.contains_key(x) {
30 self.parent.insert(x.to_string(), x.to_string());
31 self.rank.insert(x.to_string(), 0);
32 }
33 }
34
35 pub fn find(&mut self, x: &str) -> String {
36 let parent = self.parent.get(x).cloned().unwrap_or_else(|| x.to_string());
37 if parent != x {
38 let root = self.find(&parent);
40 self.parent.insert(x.to_string(), root.clone());
41 root
42 } else {
43 x.to_string()
44 }
45 }
46
47 pub fn union(&mut self, x: &str, y: &str) {
48 let root_x = self.find(x);
49 let root_y = self.find(y);
50
51 if root_x == root_y {
52 return;
53 }
54
55 let rank_x = *self.rank.get(&root_x).unwrap_or(&0);
56 let rank_y = *self.rank.get(&root_y).unwrap_or(&0);
57
58 if rank_x < rank_y {
60 self.parent.insert(root_x, root_y);
61 } else if rank_x > rank_y {
62 self.parent.insert(root_y, root_x);
63 } else {
64 self.parent.insert(root_y, root_x.clone());
65 self.rank.insert(root_x, rank_x + 1);
66 }
67 }
68}
69
70pub struct ConnectedComponents;
76
77#[derive(Debug, Clone)]
79pub struct Component {
80 pub id: String,
82 pub nodes: Vec<String>,
84 pub size: usize,
86}
87
88#[derive(Debug, Clone)]
90pub struct ComponentsResult {
91 pub components: Vec<Component>,
93 pub count: usize,
95}
96
97impl ComponentsResult {
98 pub fn largest(&self) -> Option<&Component> {
100 self.components.first()
101 }
102
103 pub fn filter_by_size(&self, min_size: usize) -> Vec<&Component> {
105 self.components
106 .iter()
107 .filter(|c| c.size >= min_size)
108 .collect()
109 }
110
111 pub fn component_of(&self, node_id: &str) -> Option<&Component> {
113 self.components
114 .iter()
115 .find(|c| c.nodes.contains(&node_id.to_string()))
116 }
117}
118
119impl ConnectedComponents {
120 pub fn find(graph: &GraphStore) -> ComponentsResult {
122 let mut uf = UnionFind::new();
123
124 for node in graph.iter_nodes() {
126 uf.make_set(&node.id);
127 }
128
129 for node in graph.iter_nodes() {
131 for (_, target, _) in graph.outgoing_edges(&node.id) {
132 uf.union(&node.id, &target);
133 }
134 }
135
136 let mut groups: HashMap<String, Vec<String>> = HashMap::new();
138 for node in graph.iter_nodes() {
139 let root = uf.find(&node.id);
140 groups.entry(root).or_default().push(node.id.clone());
141 }
142
143 let mut components: Vec<Component> = groups
145 .into_iter()
146 .map(|(id, nodes)| {
147 let size = nodes.len();
148 Component { id, nodes, size }
149 })
150 .collect();
151
152 components.sort_by_key(|b| std::cmp::Reverse(b.size));
154
155 let count = components.len();
156 ComponentsResult { components, count }
157 }
158}