diff --git a/README.md b/README.md index 7e602aa..494f4b8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,3 @@ # pyority_queue Implementations of priority queues in Python using Rust bindings for speed. - -## Purpose - -I'm doing this to learn Rust, so don't judge me too hard lol. -I've noted a few places where I'm unhappy with the implementation (mostly w.r.t. code duplication), but hopefully as I become more comfortable in Rust I can go back and fix those. -Better to have a bad implementation now than a good implementation never is my view. diff --git a/src/backing/containers/mod.rs b/src/backing/containers/mod.rs index 992fa05..74cfd32 100644 --- a/src/backing/containers/mod.rs +++ b/src/backing/containers/mod.rs @@ -1,7 +1,5 @@ mod pair; mod py_item; -mod sift_result; pub use pair::Pair; pub use py_item::PyItem; -pub use sift_result::{SiftError, SiftResult}; diff --git a/src/backing/containers/pair.rs b/src/backing/containers/pair.rs index 190cd7b..d194835 100644 --- a/src/backing/containers/pair.rs +++ b/src/backing/containers/pair.rs @@ -13,25 +13,11 @@ impl Pair { Self { data, priority } } - /// Returns the internal data. - /// It might(?) be nicer to implement this using [`From`] or [`Into`], but I don't see a way to do that using generics. + /// Retrieves the internal data. + /// It would be nicer to implement this using [`From`] or [`Into`], but I don't see a way to do that using generics. pub fn data(self) -> D { self.data } - - pub fn get_data(&self) -> &D { - &self.data - } - - /// Retrieve the priority associated with the data - pub fn get_priority(&self) -> &P { - &self.priority - } - - /// Update the priority associated with the data - pub fn set_priority(&mut self, priority: P) { - self.priority = priority - } } impl PartialOrd for Pair { diff --git a/src/backing/containers/py_item.rs b/src/backing/containers/py_item.rs index f67c853..363c853 100644 --- a/src/backing/containers/py_item.rs +++ b/src/backing/containers/py_item.rs @@ -48,8 +48,6 @@ impl PartialEq for PyItem { } } -impl Eq for PyItem {} - impl Hash for PyItem { fn hash(&self, state: &mut H) { // TODO: Should warn or fail instead of defaulting to 0 diff --git a/src/backing/containers/sift_result.rs b/src/backing/containers/sift_result.rs deleted file mode 100644 index 8b1e323..0000000 --- a/src/backing/containers/sift_result.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::fmt::{Display, Formatter, Result as fmtResult}; - -/// Indicates why a sift failed -#[derive(Debug, Clone)] -pub struct SiftError { - /// The index that couldn't be sifted - index: usize, - /// The length of the array - len: usize, -} - -impl SiftError { - /// Instantiates a `SiftError` - pub fn new(index: usize, len: usize) -> Self { - Self { index, len } - } -} - -impl Display for SiftError { - fn fmt(&self, f: &mut Formatter) -> fmtResult { - write!(f, "Could not sift index {} of {}", self.index, self.len) - } -} - -/// Whether a sift operation succeeded -pub type SiftResult = Result<(), SiftError>; diff --git a/src/backing/indexed/binary_heap.rs b/src/backing/indexed/binary_heap.rs index 2f5dbc6..84415ec 100644 --- a/src/backing/indexed/binary_heap.rs +++ b/src/backing/indexed/binary_heap.rs @@ -1,194 +1,49 @@ use std::{collections::HashMap, hash::Hash}; -use crate::backing::{ - containers::{Pair, SiftError, SiftResult}, - indexed::IndexedBacking, -}; +use crate::backing::{containers::Pair, indexed::IndexedBacking}; -pub struct IndexedBinaryHeap< - D: Hash + Eq + Clone + Send + Sync, - P: PartialOrd + Clone + Send + Sync, -> { +pub struct IndexedBinaryHeap { data: Vec>, indices: HashMap, } -impl - IndexedBinaryHeap -{ +impl IndexedBinaryHeap { pub fn new() -> Self { Self { data: Vec::new(), indices: HashMap::new(), } } - - fn sift_up(&mut self, i: usize) -> SiftResult { - print!("{i}"); - if i == 0 { - // Base case, at root so nothing to do - Ok(()) - } else if let Some(child) = self.data.get(i).cloned() { - let parent_index = (i - 1) / 2; - // Check if the heap property is violated - if child < self.data[parent_index] { - (self.data[i], self.data[parent_index]) = - (self.data[parent_index].clone(), self.data[i].clone()); - self.indices.insert(self.data[i].clone().data(), i).unwrap(); - self.indices - .insert(self.data[parent_index].clone().data(), parent_index) - .unwrap(); - self.sift_up(parent_index) - } else { - // Sift complete - Ok(()) - } - } else { - // Tried to sift a non-existent index - Err(SiftError::new(i, self.data.len())) - } - } - - fn sift_down(&mut self, i: usize) -> SiftResult { - print!("{i}"); - 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).cloned() { - 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).cloned() { - // 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].clone(); - self.indices - .insert( - self.data[smaller_child_index].clone().data(), - smaller_child_index, - ) - .unwrap(); - self.data[i] = smaller_child.clone(); - self.indices.insert(smaller_child.data(), i).unwrap(); - - // 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(()) - } - } - } - - fn delete_pair(&mut self, i: usize) -> Option> { - if i >= self.data.len() { - return None; - } - let pair = self.data[i].clone(); - if i < self.data.len() - 1 { - self.data[i] = self.data.pop().unwrap(); - if self.data[i] < pair { - self.sift_up(i).unwrap(); - } else { - self.sift_down(i).unwrap(); - } - } else { - self.data.pop().unwrap(); - } - self.indices.remove(pair.get_data()).unwrap(); - Some(pair) - } } -impl FromIterator<(D, P)> +impl FromIterator<(D, P)> for IndexedBinaryHeap { fn from_iter>(iter: T) -> Self { - let mut this = Self::new(); - for (i, (data, priority)) in iter.into_iter().enumerate() { - if let Some(prev) = this.indices.insert(data.clone(), i) { - this.indices.insert(data.clone(), prev).unwrap(); - this.data[prev] = Pair::new(data, priority); - } else { - this.data.push(Pair::new(data, priority)); - } - } - for i in (0..=(this.data.len() / 2)).rev() { - this.sift_down(i).expect("Index error during heapify"); - } - this + todo!() } } -impl IndexedBacking +impl IndexedBacking for IndexedBinaryHeap { fn len(&self) -> usize { - self.data.len() + todo!() } fn contains(&self, data: &D) -> bool { - self.indices.contains_key(data) + todo!() } fn set(&mut self, data: D, priority: P) { - if let Some(index) = self.indices.get(&data) { - let pair = self.data.get_mut(*index).unwrap(); - let old_priority = pair.get_priority(); - if priority < *old_priority { - pair.set_priority(priority); - self.sift_up(*index).unwrap(); - } else { - pair.set_priority(priority); - self.sift_down(*index).unwrap(); - } - } else { - let final_index = self.data.len(); - if let Some(_) = self.indices.insert(data.clone(), final_index) { - panic!("Item was not consistently hashed") - } - self.data.push(Pair::new(data, priority)); - self.sift_up(final_index).unwrap(); - } + todo!() } fn remove(&mut self, data: D) -> Option

{ - if let Some(index) = self.indices.get(&data) { - if let Some(pair) = self.delete_pair(*index) { - Some(pair.get_priority().clone()) - } else { - None - } - } else { - None - } + todo!() } fn pop(&mut self) -> Option { - if let Some(pair) = self.delete_pair(0) { - Some(pair.data()) - } else { - None - } + todo!() } } diff --git a/src/backing/pure/binary_heap.rs b/src/backing/pure/binary_heap.rs index 2b43ec0..cd84f18 100644 --- a/src/backing/pure/binary_heap.rs +++ b/src/backing/pure/binary_heap.rs @@ -1,7 +1,32 @@ -use crate::backing::containers::{SiftError, SiftResult}; +use std::fmt; use super::PureBacking; +/// 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>; + /// A binary min-heap backed by an array #[derive(Debug)] pub struct BinaryHeap {