use std::cmp::Ordering;
use std::usize;
pub struct MinHeap<K> {
heap: Vec<(usize, K)>,
positions: Vec<usize>,
}
impl<K: PartialOrd + Copy> MinHeap<K> {
pub fn new() -> Self {
MinHeap {
heap: Vec::new(),
positions: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.heap.is_empty()
}
pub fn len(&self) -> usize {
self.heap.len()
}
pub fn clear(&mut self) {
for &(id, _) in &self.heap {
self.positions[id] = usize::MAX;
}
self.heap.clear();
}
pub fn build_heap(items: Vec<(usize, K)>) -> Self {
let heap = items;
let pos_max = heap.iter().map(|(id, _)| *id).max().unwrap_or(0);
let mut positions = vec![usize::MAX; pos_max + 1];
for (idx, (id, _)) in heap.iter().enumerate() {
positions[*id] = idx;
}
let mut min_heap = MinHeap { heap, positions };
let n = min_heap.heap.len();
if n > 1 {
for i in (0..=(n / 2 - 1)).rev() {
min_heap.bubble_down(i);
}
}
min_heap
}
pub fn insert(&mut self, item: (usize, K)) {
self.heap.push(item);
let idx = self.heap.len() - 1;
let id = self.heap[idx].0;
if id >= self.positions.len() {
self.positions.resize(id + 1, usize::MAX);
}
self.positions[id] = idx;
self.bubble_up(idx)
}
pub fn delete_min(&mut self) -> Option<(usize, K)> {
if self.heap.is_empty() {
return None;
}
let last_item = self.heap.len() - 1;
self.heap.swap(0, last_item);
let (min_id, min_key) = self.heap.pop().unwrap();
self.positions[min_id] = usize::MAX;
if !self.heap.is_empty() {
let root_id = self.heap[0].0;
self.positions[root_id] = 0;
self.bubble_down(0);
}
return Some((min_id, min_key));
}
pub fn get_min(&self) -> Option<&(usize, K)> {
self.heap.get(0)
}
pub fn bubble_up(&mut self, mut index: usize) {
while index > 0 {
let parent = (index - 1) / 2;
if self.heap[index]
.1
.partial_cmp(&self.heap[parent].1)
.unwrap()
== Ordering::Less
{
self.heap.swap(index, parent);
let child_id = self.heap[index].0;
let parent_id = self.heap[parent].0;
self.positions[child_id] = index;
self.positions[parent_id] = parent;
index = parent;
} else {
break;
}
}
}
pub fn bubble_down(&mut self, mut index: usize) {
let heap_len = self.heap.len();
loop {
let left_child = (2 * index) + 1;
let right_child = (2 * index) + 2;
if left_child >= heap_len {
break;
}
let smaller_child: usize;
if right_child < heap_len
&& self.heap[right_child]
.1
.partial_cmp(&self.heap[left_child].1)
.unwrap()
== Ordering::Less
{
smaller_child = right_child;
} else {
smaller_child = left_child;
}
if self.heap[smaller_child]
.1
.partial_cmp(&self.heap[index].1)
.unwrap()
== Ordering::Less
{
let child_id = self.heap[smaller_child].0;
let parent_id = self.heap[index].0;
self.heap.swap(smaller_child, index);
self.positions[parent_id] = smaller_child;
self.positions[child_id] = index;
index = smaller_child;
} else {
break;
}
}
}
pub fn decrease_key(&mut self, id: usize, new_key: K) {
let pos_id = self.positions[id];
self.heap[pos_id].1 = new_key;
self.bubble_up(pos_id);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert_once() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.insert((0, 42));
assert_eq!(mh.heap.len(), 1);
assert_eq!(mh.heap[0], (0, 42));
assert_eq!(mh.positions.len(), 1);
assert_eq!(mh.positions[0], 0);
}
#[test]
fn test_insert_bubble_up() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.insert((5, 69));
mh.insert((3, 8));
assert_eq!(mh.heap, vec![(3, 8), (5, 69)]);
assert_eq!(mh.positions[3], 0);
assert_eq!(mh.positions[5], 1);
}
#[test]
fn test_get_min_peek_only() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.insert((0, 20));
mh.insert((1, 10));
let first = *mh.get_min().unwrap();
let second = *mh.get_min().unwrap();
assert_eq!(first, (1, 10));
assert_eq!(second, (1, 10));
assert_eq!(mh.heap.len(), 2);
}
#[test]
fn test_delete_min_basic() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.insert((0, 20));
mh.insert((1, 10));
mh.insert((2, 30));
let min = mh.delete_min().unwrap();
assert_eq!(min, (1, 10));
assert_eq!(*mh.get_min().unwrap(), (0, 20));
assert_eq!(mh.positions[0], 0);
assert_eq!(mh.positions[2], 1);
}
#[test]
fn test_delete_min_empty() {
let mut mh: MinHeap<i32> = MinHeap::new();
assert!(mh.delete_min().is_none());
}
#[test]
fn test_bubble_up_manual() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.heap = vec![(0, 10), (1, 5)];
mh.positions = vec![0, 1];
mh.bubble_up(1);
assert_eq!(mh.heap, vec![(1, 5), (0, 10)]);
assert_eq!(mh.positions, vec![1, 0]);
}
#[test]
fn test_bubble_down_manual() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.heap = vec![(0, 50), (1, 20), (2, 30)];
mh.positions = vec![0, 1, 2];
mh.bubble_down(0);
assert_eq!(mh.heap[0], (1, 20));
assert_eq!(mh.positions[1], 0);
assert_eq!(mh.positions[0], 1);
}
#[test]
fn test_mixed_operations() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.insert((3, 15));
mh.insert((2, 25));
mh.insert((5, 5));
assert_eq!(*mh.get_min().unwrap(), (5, 5));
let order: Vec<_> = (0..3).map(|_| mh.delete_min().unwrap()).collect();
assert_eq!(order, vec![(5, 5), (3, 15), (2, 25)]);
assert!(mh.delete_min().is_none());
}
#[test]
fn test_build_heap() {
let items = vec![(2, 50), (0, 10), (3, 20), (1, 5)];
let mut mh = MinHeap::build_heap(items);
assert_eq!(*mh.get_min().unwrap(), (1, 5));
assert_eq!(mh.positions[1], 0);
assert_eq!(mh.heap.len(), 4);
let order: Vec<_> = (0..4).map(|_| mh.delete_min().unwrap()).collect();
assert_eq!(order, vec![(1, 5), (0, 10), (3, 20), (2, 50)]);
assert!(mh.delete_min().is_none());
}
#[test]
fn test_is_empty() {
let mut mh: MinHeap<i32> = MinHeap::new();
assert!(mh.is_empty());
mh.insert((0, 100));
assert!(!mh.is_empty());
mh.delete_min();
assert!(mh.is_empty());
}
#[test]
fn test_decrease_key() {
let mut mh: MinHeap<i32> = MinHeap::new();
mh.insert((0, 100));
mh.insert((1, 200));
mh.insert((2, 300));
assert_eq!(*mh.get_min().unwrap(), (0, 100));
mh.decrease_key(2, 50);
assert_eq!(*mh.get_min().unwrap(), (2, 50));
assert_eq!(mh.positions[2], 0);
}
#[test]
fn test_float_keys_basic() {
let mut mh: MinHeap<f64> = MinHeap::new();
mh.insert((0, 3.14));
mh.insert((1, 2.71));
mh.insert((2, -1.0));
assert_eq!(mh.get_min(), Some(&(2, -1.0)));
let mut seq = Vec::new();
while let Some((id, key)) = mh.delete_min() {
seq.push((id, key));
}
assert_eq!(seq, vec![(2, -1.0), (1, 2.71), (0, 3.14),]);
}
#[test]
fn test_float_decrease_key() {
let mut mh: MinHeap<f64> = MinHeap::new();
mh.insert((0, 10.0));
mh.insert((1, 20.0));
mh.decrease_key(1, 5.0);
assert_eq!(mh.get_min(), Some(&(1, 5.0)));
let first = mh.delete_min().unwrap();
let second = mh.delete_min().unwrap();
assert_eq!(first, (1, 5.0));
assert_eq!(second, (0, 10.0));
}
}