use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::mem::swap;
pub type BinaryMaxHeap<T> = BinaryHeap<T, Max<T>>;
pub type BinaryMinHeap<T> = BinaryHeap<T, Min<T>>;
pub struct BinaryHeap<T, H> {
data: Vec<T>,
_heap_property: PhantomData<H>,
}
pub struct Max<T>(PhantomData<T>);
pub struct Min<T>(PhantomData<T>);
pub trait HeapProperty<T> {
const NAME: &'static str;
fn property_upheld(lhs: &T, rhs: &T) -> bool;
}
impl<T, H> BinaryHeap<T, H> {
pub const fn new() -> Self {
Self {
data: Vec::new(),
_heap_property: PhantomData,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
_heap_property: PhantomData,
}
}
pub fn push(&mut self, value: T)
where
T: PartialOrd,
H: HeapProperty<T>,
{
let index = self.data.len();
self.data.push(value);
self.upheap(index);
}
pub fn peek(&self) -> Option<&T> {
self.data.get(0)
}
pub fn pop(&mut self) -> Option<T>
where
T: PartialOrd,
H: HeapProperty<T>,
{
if self.data.is_empty() {
return None;
}
let last_index = self.data.len() - 1;
self.data.swap(0, last_index);
let extracted_value = self.data.pop();
if !self.data.is_empty() {
self.downheap(0);
}
extracted_value
}
pub fn push_pop(&mut self, mut value: T) -> T
where
T: PartialOrd,
H: HeapProperty<T>,
{
if self.data.is_empty() {
return value;
}
if H::property_upheld(&value, &self.data[0]) {
return value;
}
swap(&mut self.data[0], &mut value);
self.downheap(0);
value
}
pub fn contains(&self, value: &T) -> bool
where
T: PartialEq,
{
self.data.contains(value)
}
pub fn remove(&mut self, value: &T) -> bool
where
T: PartialEq + PartialOrd,
H: HeapProperty<T>,
{
self.remove_where(|x| x == value).is_some()
}
pub fn remove_where<F>(&mut self, predicate: F) -> Option<T>
where
T: PartialEq + PartialOrd,
H: HeapProperty<T>,
F: FnMut(&T) -> bool,
{
if self.data.is_empty() {
return None;
}
let last_index = self.data.len() - 1;
if let Some(index) = self.data.iter().position(predicate) {
self.data.swap(index, last_index);
let previous_value = self.data.pop().expect("the value exists");
if index == last_index {
return Some(previous_value);
}
let up_heapify = H::property_upheld(&self.data[index], &previous_value);
if up_heapify {
self.upheap(index);
} else {
self.downheap(index);
}
Some(previous_value)
} else {
None
}
}
pub fn replace(&mut self, value: &T, replacement: T) -> Option<T>
where
T: PartialEq + PartialOrd,
H: HeapProperty<T>,
{
self.replace_where(|x| x == value, replacement)
}
pub fn replace_where<F>(&mut self, predicate: F, mut replacement: T) -> Option<T>
where
T: PartialEq + PartialOrd,
H: HeapProperty<T>,
F: FnMut(&T) -> bool,
{
if self.data.is_empty() {
return None;
}
if let Some(index) = self.data.iter().position(predicate) {
let downheap = H::property_upheld(&self.data[index], &replacement);
swap(&mut self.data[index], &mut replacement);
if downheap {
self.downheap(index);
} else {
self.upheap(index);
}
Some(replacement)
} else {
None
}
}
pub fn replace_with<R>(&mut self, value: &T, replacement: R) -> bool
where
T: PartialEq + PartialOrd,
H: HeapProperty<T>,
R: FnMut(&mut T),
{
self.replace_where_with(|x| x == value, replacement)
}
pub fn replace_where_with<F, R>(&mut self, predicate: F, mut replacement: R) -> bool
where
T: PartialEq + PartialOrd,
H: HeapProperty<T>,
F: FnMut(&T) -> bool,
R: FnMut(&mut T),
{
if self.data.is_empty() {
return false;
}
if let Some(index) = self.data.iter().position(predicate) {
replacement(&mut self.data[index]);
let _ = self.upheap(index) || self.downheap(index);
true
} else {
false
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
fn upheap(&mut self, mut index: usize) -> bool
where
T: PartialOrd,
H: HeapProperty<T>,
{
debug_assert!(index < self.data.len());
let mut changed = false;
while index > 0 {
let parent_idx = self
.get_parent_idx(index)
.expect("since the tree was not empty before the insert, the parent must exist");
let parent = self
.data
.get(parent_idx)
.expect("since the tree was not empty before the insert, the parent must exist");
if H::property_upheld(&parent, &self.data[index]) {
break;
}
self.data.swap(parent_idx, index);
index = parent_idx;
changed = true;
}
changed
}
fn downheap(&mut self, mut index: usize) -> bool
where
T: PartialOrd,
H: HeapProperty<T>,
{
debug_assert!(index < self.data.len());
let mut changed = false;
loop {
let left_child_idx = self.get_left_child_idx(index);
let right_child_idx = self.get_right_child_idx(index);
let current = &self.data[index];
match (left_child_idx, right_child_idx) {
(Some(left), Some(right)) => {
let left_child = &self.data[left];
let right_child = &self.data[right];
if H::property_upheld(¤t, left_child)
&& H::property_upheld(current, right_child)
{
break;
}
if H::property_upheld(left_child, right_child) {
self.data.swap(index, left);
index = left;
} else {
self.data.swap(index, right);
index = right;
}
changed = true;
}
(Some(child), None) => {
let left_child = &self.data[child];
if H::property_upheld(current, left_child) {
break;
}
self.data.swap(index, child);
debug_assert!(self.get_left_child_idx(child).is_none());
changed = true;
}
(None, Some(_)) => unreachable!("the tree cannot have only a right child"),
(None, None) => break,
}
}
changed
}
const fn get_left_child_idx_unchecked(index: usize) -> usize {
2 * index + 1
}
fn get_left_child_idx(&self, index: usize) -> Option<usize> {
let idx = Self::get_left_child_idx_unchecked(index);
if idx < self.data.len() {
Some(idx)
} else {
None
}
}
const fn get_right_child_idx_unchecked(index: usize) -> usize {
2 * index + 2
}
fn get_right_child_idx(&self, index: usize) -> Option<usize> {
let idx = Self::get_right_child_idx_unchecked(index);
if idx < self.data.len() {
Some(idx)
} else {
None
}
}
fn get_parent_idx(&self, index: usize) -> Option<usize> {
if index == 0 || index >= self.data.len() {
return None;
}
Some((index - 1) / 2)
}
}
impl<T, H> FromIterator<T> for BinaryHeap<T, H>
where
T: PartialOrd,
H: HeapProperty<T>,
{
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
<Self as From<Vec<T>>>::from(iter.into_iter().collect())
}
}
impl<T, H> From<Vec<T>> for BinaryHeap<T, H>
where
T: PartialOrd,
H: HeapProperty<T>,
{
fn from(value: Vec<T>) -> Self {
let mut tree = Self {
data: value,
_heap_property: PhantomData,
};
let length = tree.data.len();
for i in (0..=(length / 2)).rev() {
tree.downheap(i);
}
tree
}
}
impl<T, H> Debug for BinaryHeap<T, H>
where
T: Debug,
H: HeapProperty<T>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!("Binary{}Heap", H::NAME))
.field("data", &self.data)
.finish()
}
}
impl<T, H> Default for BinaryHeap<T, H> {
fn default() -> Self {
Self::new()
}
}
impl<T, H> Clone for BinaryHeap<T, H>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
_heap_property: PhantomData,
}
}
}
impl<T, H> AsRef<[T]> for BinaryHeap<T, H> {
fn as_ref(&self) -> &[T] {
&self.data
}
}
impl<T> HeapProperty<T> for Max<T>
where
T: PartialOrd,
{
const NAME: &'static str = "Max";
fn property_upheld(lhs: &T, rhs: &T) -> bool {
lhs >= rhs
}
}
impl<T> HeapProperty<T> for Min<T>
where
T: PartialOrd,
{
const NAME: &'static str = "Min";
fn property_upheld(lhs: &T, rhs: &T) -> bool {
lhs <= rhs
}
}