Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Overengineered better grouping algorithm and reducing number of inter…
…section points #19
- Loading branch information
Showing
5 changed files
with
191 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
pub struct DisjointSets<T> { | ||
elements: Vec<T>, | ||
parent_indices: Vec<usize>, | ||
ranks: Vec<usize>, | ||
is_sorted: bool | ||
} | ||
|
||
impl<T> DisjointSets<T> { | ||
pub fn from_individuals(individuals: Vec<T>) -> Self { | ||
DisjointSets{ | ||
parent_indices: (0..individuals.len()).into_iter().collect(), | ||
ranks: vec![0; individuals.len()], | ||
elements: individuals, | ||
is_sorted: true | ||
} | ||
} | ||
|
||
fn find_root(&mut self, idx: usize) -> usize { | ||
if self.parent_indices[idx] != idx { | ||
let parent = self.parent_indices[idx]; | ||
self.parent_indices[idx] = self.find_root(parent); | ||
} | ||
self.parent_indices[idx] | ||
} | ||
|
||
fn union(&mut self, idx_a: usize, idx_b: usize) { | ||
let root_a = self.find_root(idx_a); | ||
let root_b = self.find_root(idx_b); | ||
|
||
if root_a != root_b { | ||
if self.ranks[root_a] < self.ranks[root_b] { | ||
self.parent_indices[root_a] = root_b; | ||
} else if self.ranks[root_a] > self.ranks[root_b] { | ||
self.parent_indices[root_b] = root_a; | ||
} else { | ||
self.parent_indices[root_b] = root_a; | ||
self.ranks[root_a] += 1; | ||
} | ||
} | ||
|
||
self.is_sorted = false; | ||
} | ||
|
||
pub fn union_all_with<F: Fn(&T, &T) -> bool>(&mut self, should_union: F) { | ||
let len = self.elements.len(); | ||
for idx_a in 0..len { | ||
for idx_b in (idx_a + 1)..len { | ||
if should_union(&self.elements[idx_a], &self.elements[idx_b]) { | ||
self.union(idx_a, idx_b); | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn ensure_sorted(&mut self) { | ||
if !self.is_sorted { | ||
// counting sort | ||
let mut root_occurences = vec![0; self.elements.len()]; | ||
|
||
for idx in 0..self.elements.len() { | ||
root_occurences[self.find_root(idx)] += 1; | ||
}; | ||
|
||
let mut root_start_index = root_occurences; | ||
|
||
let mut current_start_index = 0; | ||
#[allow(needless_range_loop)] | ||
for root in 0..self.elements.len() { | ||
// still occurence count | ||
let next_start_index = current_start_index + root_start_index[root]; | ||
// now start index | ||
root_start_index[root] = current_start_index; | ||
current_start_index = next_start_index; | ||
} | ||
|
||
let mut new_elements = Vec::with_capacity(self.elements.len()); | ||
let mut new_ranks = Vec::with_capacity(self.elements.len()); | ||
let mut old_to_new_idx_map = vec![0; self.elements.len()]; | ||
let mut new_to_old_idx_map = vec![0; self.elements.len()]; | ||
|
||
#[allow(needless_range_loop)] | ||
for idx in 0..self.elements.len() { | ||
let root = self.find_root(idx); | ||
let new_idx = root_start_index[root]; | ||
root_start_index[root] += 1; | ||
old_to_new_idx_map[idx] = new_idx; | ||
new_to_old_idx_map[new_idx] = idx; | ||
|
||
unsafe { | ||
::std::ptr::copy_nonoverlapping(&self.elements[idx], new_elements.as_mut_ptr().offset(new_idx as isize), 1); | ||
::std::ptr::copy_nonoverlapping(&self.ranks[idx], new_ranks.as_mut_ptr().offset(new_idx as isize), 1); | ||
} | ||
} | ||
|
||
unsafe { | ||
new_elements.set_len(self.elements.len()); | ||
new_ranks.set_len(self.elements.len()); | ||
// prevents items to be dropped, since they live on in new_elements | ||
self.elements.set_len(0); | ||
} | ||
|
||
self.elements = new_elements; | ||
self.ranks = new_ranks; | ||
self.parent_indices = new_to_old_idx_map.iter().map(|&old_idx| old_to_new_idx_map[self.parent_indices[old_idx]]).collect(); | ||
|
||
self.is_sorted = true; | ||
} | ||
} | ||
|
||
pub fn sets(&mut self) -> SetsIterator<T> { | ||
self.ensure_sorted(); | ||
SetsIterator{ | ||
elements: &self.elements, | ||
input_iter: self.parent_indices.iter().enumerate().peekable() | ||
} | ||
} | ||
} | ||
|
||
pub struct SetsIterator<'a, T: 'a> { | ||
elements: &'a Vec<T>, | ||
input_iter: ::std::iter::Peekable<::std::iter::Enumerate<::std::slice::Iter<'a, usize>>> | ||
} | ||
|
||
impl<'a, T: 'a> Iterator for SetsIterator<'a, T> { | ||
type Item = &'a [T]; | ||
fn next(&mut self) -> Option<&'a [T]> { | ||
if let Some((set_start_idx, root)) = self.input_iter.next() { | ||
let mut set_end_idx = set_start_idx + 1; | ||
|
||
while self.input_iter.peek().map(|&(_, next_root)| next_root == root).unwrap_or(false) { | ||
self.input_iter.next(); | ||
set_end_idx += 1; | ||
} | ||
|
||
Some(&self.elements[set_start_idx..set_end_idx]) | ||
} else {None} | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_disjoint_sets() { | ||
let mut numbers = DisjointSets::from_individuals(vec![112, 44, 32, 66, 52, 74, 176]); | ||
numbers.union_all_with(|a, b| a % 10 == b % 10); | ||
println!("{:?}, {:?}", numbers.elements, numbers.parent_indices); | ||
numbers.ensure_sorted(); | ||
println!("{:?}, {:?}", numbers.elements, numbers.parent_indices); | ||
let sets = numbers.sets(); | ||
let set1 = [112, 32, 52]; | ||
let set2 = [44, 74]; | ||
let set3 = [66, 176]; | ||
assert!(sets.collect::<Vec<_>>() == vec![&set1[..], &set2[..], &set3[..]]); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
pub mod ui; | ||
pub mod geometry; | ||
pub mod simulation; | ||
pub mod merge_groups; | ||
pub mod disjoint_sets; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters