use std::collections::HashSet;
use std::hash::Hash;
use indexmap::IndexMap;
pub struct DisjointSet<K: Copy + Eq + Hash> {
entries: IndexMap<K, K>,
}
impl<K: Copy + Eq + Hash> DisjointSet<K> {
pub fn new() -> Self {
DisjointSet {
entries: IndexMap::new(),
}
}
pub fn union(&mut self, items: &[K]) {
if items.is_empty() {
return;
}
let root = self.find(items[0]);
for &item in &items[1..] {
let item_root = self.find(item);
if item_root != root {
self.entries.insert(item_root, root);
}
}
}
pub fn find(&mut self, item: K) -> K {
let parent = match self.entries.get(&item) {
Some(&p) => p,
None => {
self.entries.insert(item, item);
return item;
}
};
if parent == item {
return item;
}
let root = self.find(parent);
self.entries.insert(item, root);
root
}
pub fn find_opt(&mut self, item: K) -> Option<K> {
if !self.entries.contains_key(&item) {
return None;
}
Some(self.find(item))
}
pub fn has(&self, item: K) -> bool {
self.entries.contains_key(&item)
}
pub fn canonicalize(&mut self) -> IndexMap<K, K> {
let mut result = IndexMap::new();
let keys: Vec<K> = self.entries.keys().copied().collect();
for item in keys {
let root = self.find(item);
result.insert(item, root);
}
result
}
pub fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(K, K),
{
let keys: Vec<K> = self.entries.keys().copied().collect();
for item in keys {
let group = self.find(item);
f(item, group);
}
}
pub fn build_sets(&mut self) -> Vec<HashSet<K>> {
let mut group_to_index: IndexMap<K, usize> = IndexMap::new();
let mut sets: Vec<HashSet<K>> = Vec::new();
let keys: Vec<K> = self.entries.keys().copied().collect();
for item in keys {
let group = self.find(item);
let idx = match group_to_index.get(&group) {
Some(&idx) => idx,
None => {
let idx = sets.len();
group_to_index.insert(group, idx);
sets.push(HashSet::new());
idx
}
};
sets[idx].insert(item);
}
sets
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}