Add binary min-heap
This commit is contained in:
parent
28e780d274
commit
df7536b82b
2 changed files with 147 additions and 0 deletions
146
src/backing/pure/binary_heap.rs
Normal file
146
src/backing/pure/binary_heap.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::PureBacking;
|
||||||
|
|
||||||
|
/// A binary min-heap backed by an array
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BinaryHeap<T: Ord + Copy> {
|
||||||
|
data: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates why a sift failed
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct SiftError {
|
||||||
|
/// The index that couldn't be sifted
|
||||||
|
index: usize,
|
||||||
|
/// The length of the array
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SiftError {
|
||||||
|
/// Instantiates a `SiftError`
|
||||||
|
fn new(index: usize, len: usize) -> Self {
|
||||||
|
Self { index, len }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SiftError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Could not sift index {} of {}", self.index, self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether a sift operation succeeded
|
||||||
|
type SiftResult = Result<(), SiftError>;
|
||||||
|
|
||||||
|
impl<T: Ord + Copy> BinaryHeap<T> {
|
||||||
|
/// Fix an index representing a node with valid children but that may violate the heap property compared to its immediate parent
|
||||||
|
fn sift_up(&mut self, i: usize) -> SiftResult {
|
||||||
|
if i == 0 {
|
||||||
|
// Base case, at root so nothing to do
|
||||||
|
Ok(())
|
||||||
|
} else if let Some(child) = self.data.get(i).copied() {
|
||||||
|
let parent_index = (i - 1) / 2;
|
||||||
|
// Check if the heap property is violated
|
||||||
|
if child < self.data[parent_index] {
|
||||||
|
// Swap child with parent
|
||||||
|
self.data[i] = self.data[parent_index];
|
||||||
|
self.data[parent_index] = child;
|
||||||
|
|
||||||
|
// Repeat process with parent
|
||||||
|
self.sift_up(parent_index)
|
||||||
|
} else {
|
||||||
|
// Sift complete
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Tried to sift a non-existent index
|
||||||
|
Err(SiftError::new(i, self.data.len()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Fix an index representing a node with that doesn't violate the heap property, but may have immediate children that do
|
||||||
|
fn sift_down(&mut self, i: usize) -> SiftResult {
|
||||||
|
if i > self.data.len() {
|
||||||
|
// Tried to sift a non-existent index
|
||||||
|
Err(SiftError::new(i, self.data.len()))
|
||||||
|
} else {
|
||||||
|
if let Some(first_child) = self.data.get(i * 2 + 1).copied() {
|
||||||
|
let smaller_child_index;
|
||||||
|
let smaller_child;
|
||||||
|
|
||||||
|
// Find the smallest child and its index
|
||||||
|
if let Some(second_child) = self.data.get(i * 2 + 2).copied() {
|
||||||
|
// Both children, use the smaller one
|
||||||
|
if first_child < second_child {
|
||||||
|
smaller_child = first_child;
|
||||||
|
smaller_child_index = i * 2 + 1;
|
||||||
|
} else {
|
||||||
|
smaller_child = second_child;
|
||||||
|
smaller_child_index = i * 2 + 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Only one child, no choice
|
||||||
|
smaller_child = first_child;
|
||||||
|
smaller_child_index = i * 2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if smaller_child < self.data[i] {
|
||||||
|
// Swap parent with child
|
||||||
|
self.data[smaller_child_index] = self.data[i];
|
||||||
|
self.data[i] = smaller_child;
|
||||||
|
|
||||||
|
// Repeat process with child
|
||||||
|
self.sift_down(smaller_child_index)
|
||||||
|
} else {
|
||||||
|
// Heap property satisfied, we're done
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Base case, no children so nothing to do
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Ord + Copy> PureBacking<T> for BinaryHeap<T> {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { data: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, item: T) {
|
||||||
|
// Append item
|
||||||
|
self.data.push(item);
|
||||||
|
// Sift up to retain heap property
|
||||||
|
self.sift_up(self.data.len() - 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> Option<T> {
|
||||||
|
match self.data.len() {
|
||||||
|
// No extra processing
|
||||||
|
0 | 1 => self.data.pop(),
|
||||||
|
_ => {
|
||||||
|
let last = self
|
||||||
|
.data
|
||||||
|
.pop()
|
||||||
|
.expect("Vector claimed not to be empty but was");
|
||||||
|
let root = self
|
||||||
|
.data
|
||||||
|
.get_mut(0)
|
||||||
|
.expect("Vector claimed to have multiple items but didn't");
|
||||||
|
|
||||||
|
// Move final item to the root and sift down to regain heap property
|
||||||
|
let best = *root;
|
||||||
|
*root = last;
|
||||||
|
self.sift_down(0).unwrap();
|
||||||
|
|
||||||
|
// Return original root
|
||||||
|
Some(best)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
/// Data structures for the "pure" min-queues, supporting duplicates but no arbitrary updates
|
/// Data structures for the "pure" min-queues, supporting duplicates but no arbitrary updates
|
||||||
|
pub mod binary_heap;
|
||||||
|
|
||||||
/// A data structure usable for backing a "pure" queue
|
/// A data structure usable for backing a "pure" queue
|
||||||
pub trait PureBacking<T: Ord> {
|
pub trait PureBacking<T: Ord> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue