mod algorithm;
#[cfg(test)]
mod unit_test;
use crate::utils::read_lines;
pub use algorithm::UnionFindAlgorithm;
use std::path::Path;
#[derive(Debug, Default)]
pub struct UnionFind {
nb_objects: usize,
algo: UnionFindAlgorithm,
ids: Vec<usize>,
size: Vec<usize>,
}
impl UnionFind {
pub fn new() -> Self {
let nb = 1;
Self {
nb_objects: nb,
algo: UnionFindAlgorithm::default(),
ids: (0..nb).collect::<Vec<usize>>(),
size: vec![1; nb],
}
}
pub fn with_capacity(nb: usize, algorithm: UnionFindAlgorithm) -> Self {
match algorithm {
UnionFindAlgorithm::QuickFind => Self {
nb_objects: nb,
algo: algorithm,
ids: (0..nb).collect::<Vec<usize>>(),
size: Vec::new(),
},
_ => Self {
nb_objects: nb,
algo: algorithm,
ids: (0..nb).collect::<Vec<usize>>(),
size: vec![1; nb],
},
}
}
pub fn algo(&self) -> UnionFindAlgorithm {
self.algo
}
pub fn len(&self) -> usize {
self.nb_objects
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn from_file<P>(filename: P, sep: char, algo: UnionFindAlgorithm) -> Self
where
P: AsRef<Path>,
{
let mut nb_iter = 0;
let mut uf = UnionFind::new();
if let Ok(lines) = read_lines(filename) {
for (pos, line) in lines.enumerate() {
if let Ok(row) = line {
let values = row.split(sep).collect::<Vec<&str>>();
if pos == 0 {
let nb_objects = values[0].parse::<usize>().unwrap();
uf = UnionFind::with_capacity(nb_objects, algo);
} else {
let (p, q) = (
values[0].parse::<usize>().unwrap(),
values[1].parse::<usize>().unwrap(),
);
if !uf.connected(p, q) {
uf.union(p, q);
println!("{nb_iter}");
nb_iter += 1
}
}
}
}
}
uf
}
pub fn root(&mut self, mut i: usize) -> usize {
if let UnionFindAlgorithm::QuickFind = self.algo {
self.ids[i]
} else if let UnionFindAlgorithm::WeightedQuickUnionPathComp = self.algo {
while i != self.ids[i] {
self.ids[i] = self.ids[self.ids[i]];
i = self.ids[i];
}
i
} else {
while i != self.ids[i] {
i = self.ids[i];
}
i
}
}
pub fn connected(&mut self, p: usize, q: usize) -> bool {
if let UnionFindAlgorithm::QuickFind = self.algo {
self.ids[p] == self.ids[q]
} else {
self.root(p) == self.root(q)
}
}
pub fn union(&mut self, p: usize, q: usize) {
match self.algo {
UnionFindAlgorithm::QuickFind => {
let pid: usize = self.ids[p];
let qid: usize = self.ids[q];
for i in 0..self.ids.len() {
if self.ids[i] == pid {
self.ids[i] = qid;
}
}
}
UnionFindAlgorithm::QuickUnion => {
let i = self.root(p);
let j = self.root(q);
self.ids[i] = j;
}
_ => {
let i = self.root(p);
let j = self.root(q);
if self.size[i] < self.size[j] {
self.ids[i] = j;
self.size[j] += self.size[i];
} else {
self.ids[j] = i;
self.size[i] += self.size[j];
}
}
}
}
}