use alloc::{collections::BTreeMap, vec, vec::Vec};
use core::cmp::Ordering;
use oxgraph_topology::{ElementIndex, ElementSuccessors, TopologyBase};
fn find(parent: &mut [usize], mut cursor: usize) -> usize {
while parent[cursor] != cursor {
parent[cursor] = parent[parent[cursor]];
cursor = parent[cursor];
}
cursor
}
fn union(parent: &mut [usize], rank: &mut [u8], left: usize, right: usize) {
let left_root = find(parent, left);
let right_root = find(parent, right);
if left_root == right_root {
return;
}
match rank[left_root].cmp(&rank[right_root]) {
Ordering::Less => parent[left_root] = right_root,
Ordering::Greater => parent[right_root] = left_root,
Ordering::Equal => {
parent[right_root] = left_root;
rank[left_root] += 1;
}
}
}
pub fn connected_components<G>(
graph: &G,
elements: &[<G as TopologyBase>::ElementId],
) -> Vec<Vec<<G as TopologyBase>::ElementId>>
where
G: ElementIndex + ElementSuccessors,
{
let bound = graph.element_bound();
let mut member = vec![false; bound];
let mut nodes: Vec<G::ElementId> = Vec::new();
for &element in elements {
let index = graph.element_index(element);
if index < bound && !member[index] {
member[index] = true;
nodes.push(element);
}
}
let mut parent: Vec<usize> = (0..bound).collect();
let mut rank = vec![0u8; bound];
for &node in &nodes {
let source = graph.element_index(node);
for successor in graph.element_successors(node) {
let target = graph.element_index(successor);
if target < bound && member[target] {
union(&mut parent, &mut rank, source, target);
}
}
}
let mut groups: BTreeMap<usize, Vec<G::ElementId>> = BTreeMap::new();
for &node in &nodes {
let root = find(&mut parent, graph.element_index(node));
groups.entry(root).or_default().push(node);
}
groups.into_values().collect()
}