Compare commits
No commits in common. "70295da0ba0a5b6ab347d3fef7d3dfa956510694" and "ebfce09c0e93c1ff96590e041bf3a9a0cd97a3fd" have entirely different histories.
70295da0ba
...
ebfce09c0e
7 changed files with 39 additions and 209 deletions
|
@ -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.
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -13,25 +13,11 @@ impl<D: Clone, P: PartialOrd + Clone> Pair<D, P> {
|
|||
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<D: Clone, P: PartialOrd + Clone> PartialOrd for Pair<D, P> {
|
||||
|
|
|
@ -48,8 +48,6 @@ impl PartialEq for PyItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl Eq for PyItem {}
|
||||
|
||||
impl Hash for PyItem {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// TODO: Should warn or fail instead of defaulting to 0
|
||||
|
|
|
@ -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>;
|
|
@ -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<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> {
|
||||
data: Vec<Pair<D, P>>,
|
||||
indices: HashMap<D, usize>,
|
||||
}
|
||||
|
||||
impl<D: Hash + Eq + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync>
|
||||
IndexedBinaryHeap<D, P>
|
||||
{
|
||||
impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> IndexedBinaryHeap<D, P> {
|
||||
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<Pair<D, P>> {
|
||||
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<D: Hash + Eq + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> FromIterator<(D, P)>
|
||||
impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> FromIterator<(D, P)>
|
||||
for IndexedBinaryHeap<D, P>
|
||||
{
|
||||
fn from_iter<T: IntoIterator<Item = (D, P)>>(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<D: Hash + Eq + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> IndexedBacking<D, P>
|
||||
impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> IndexedBacking<D, P>
|
||||
for IndexedBinaryHeap<D, P>
|
||||
{
|
||||
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<P> {
|
||||
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<D> {
|
||||
if let Some(pair) = self.delete_pair(0) {
|
||||
Some(pair.data())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T: PartialOrd + Clone + Send + Sync> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue