use std::cell::RefCell;
use std::cmp::Ordering as CmpOrdering;
use std::collections::HashMap;
use std::fmt::Debug;
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HeapError {
InvalidKey,
NodeNotFound,
NodeInvalid,
HeapEmpty,
KeyComparisonError,
}
pub type HeapResult<T> = Result<T, HeapError>;
pub trait HeapKey: PartialOrd + Clone + Debug + 'static {}
impl<T> HeapKey for T where T: PartialOrd + Clone + Debug + 'static {}
#[derive(Debug)]
pub struct Node<T: HeapKey> {
pub key: T,
degree: usize,
marked: bool,
parent: Option<Weak<RefCell<Node<T>>>>,
children: Vec<Rc<RefCell<Node<T>>>>,
id: usize,
}
impl<T: HeapKey> Node<T> {
fn new(key: T, id: usize) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Node {
key,
degree: 0,
marked: false,
parent: None,
children: Vec::new(),
id,
}))
}
}
pub trait NodeRef<T: HeapKey> {
fn validate(&self, heap: &GenericFibonacciHeap<T>) -> bool;
fn get_key(&self) -> T;
fn get_id(&self) -> usize;
}
impl<T: HeapKey> NodeRef<T> for Rc<RefCell<Node<T>>> {
fn validate(&self, heap: &GenericFibonacciHeap<T>) -> bool {
heap.validate_node(self)
}
fn get_key(&self) -> T {
self.borrow().key.clone()
}
fn get_id(&self) -> usize {
self.borrow().id
}
}
#[derive(Debug)]
pub struct GenericFibonacciHeap<T: HeapKey> {
min: Option<Rc<RefCell<Node<T>>>>,
root_list: Vec<Rc<RefCell<Node<T>>>>,
node_count: usize,
next_id: AtomicUsize,
active_nodes: HashMap<usize, Weak<RefCell<Node<T>>>>,
}
impl<T: HeapKey> Default for GenericFibonacciHeap<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: HeapKey> GenericFibonacciHeap<T> {
pub fn new() -> Self {
GenericFibonacciHeap {
min: None,
root_list: Vec::new(),
node_count: 0,
next_id: AtomicUsize::new(0),
active_nodes: HashMap::new(),
}
}
pub fn validate_node(&self, node: &Rc<RefCell<Node<T>>>) -> bool {
let node_id = node.borrow().id;
if let Some(weak_ref) = self.active_nodes.get(&node_id)
&& let Some(strong_ref) = weak_ref.upgrade()
{
return Rc::ptr_eq(&strong_ref, node);
}
false
}
pub fn insert(&mut self, key: T) -> HeapResult<Rc<RefCell<Node<T>>>> {
let id = self.next_id.fetch_add(1, AtomicOrdering::SeqCst);
let node = Node::new(key, id);
self.active_nodes.insert(id, Rc::downgrade(&node));
self.root_list.push(Rc::clone(&node));
self.node_count += 1;
match &self.min {
Some(min) if node.borrow().key < min.borrow().key => {
self.min = Some(Rc::clone(&node));
}
None => self.min = Some(Rc::clone(&node)),
_ => (),
}
Ok(node)
}
pub fn merge(&mut self, other: GenericFibonacciHeap<T>) {
self.root_list.extend(other.root_list);
self.node_count += other.node_count;
self.active_nodes.extend(other.active_nodes);
if let Some(other_min) = other.min {
match &self.min {
Some(self_min) if other_min.borrow().key < self_min.borrow().key => {
self.min = Some(other_min);
}
None => self.min = Some(other_min),
_ => (),
}
}
}
pub fn extract_min(&mut self) -> Option<T> {
let min_node = self.min.take()?;
let min_key = min_node.borrow().key.clone();
let min_id = min_node.borrow().id;
self.active_nodes.remove(&min_id);
let children = std::mem::take(&mut min_node.borrow_mut().children);
for child in children {
child.borrow_mut().parent = None;
self.root_list.push(child);
}
self.root_list.retain(|node| !Rc::ptr_eq(node, &min_node));
self.node_count -= 1;
if self.root_list.is_empty() {
self.min = None;
} else {
self.consolidate();
}
Some(min_key)
}
fn consolidate(&mut self) {
let max_degree = (self.node_count as f64).log2() as usize + 2;
let mut degree_table: Vec<Option<Rc<RefCell<Node<T>>>>> = vec![None; max_degree];
let roots = std::mem::take(&mut self.root_list);
for root in roots {
let mut current = root;
let mut degree = current.borrow().degree;
if degree >= degree_table.len() {
degree_table.resize(degree + 1, None);
}
while let Some(existing) = degree_table[degree].take() {
if current.borrow().key < existing.borrow().key {
self.link(&existing, ¤t);
} else {
self.link(¤t, &existing);
current = existing;
}
degree = current.borrow().degree;
if degree >= degree_table.len() {
degree_table.resize(degree + 1, None);
}
}
degree_table[degree] = Some(Rc::clone(¤t));
}
self.root_list = degree_table.into_iter().flatten().collect();
self.min = self.root_list.iter()
.reduce(|acc, node| {
match node.borrow().key.partial_cmp(&acc.borrow().key) {
Some(CmpOrdering::Less) => node,
_ => acc,
}
})
.cloned();
}
fn link(&mut self, child: &Rc<RefCell<Node<T>>>, parent: &Rc<RefCell<Node<T>>>) {
self.root_list.retain(|node| !Rc::ptr_eq(node, child));
child.borrow_mut().parent = Some(Rc::downgrade(parent));
child.borrow_mut().marked = false;
parent.borrow_mut().children.push(Rc::clone(child));
parent.borrow_mut().degree += 1;
}
pub fn decrease_key(&mut self, node: &Rc<RefCell<Node<T>>>, new_key: T) -> HeapResult<()> {
if !self.validate_node(node) {
return Err(HeapError::NodeNotFound);
}
let old_key = node.borrow().key.clone();
match old_key.partial_cmp(&new_key) {
Some(CmpOrdering::Less) | Some(CmpOrdering::Equal) => {
return Err(HeapError::InvalidKey);
}
Some(CmpOrdering::Greater) => {
}
None => {
return Err(HeapError::KeyComparisonError);
}
}
node.borrow_mut().key = new_key.clone();
if let Some(parent_weak) = &node.borrow().parent
&& let Some(parent) = parent_weak.upgrade()
&& new_key < parent.borrow().key
{
self.cut(node, &parent);
self.cascading_cut(&parent);
}
match &self.min {
Some(min) if new_key < min.borrow().key => {
self.min = Some(Rc::clone(node));
}
None => self.min = Some(Rc::clone(node)),
_ => (),
}
Ok(())
}
fn cut(&mut self, node: &Rc<RefCell<Node<T>>>, parent: &Rc<RefCell<Node<T>>>) {
parent
.borrow_mut()
.children
.retain(|child| !Rc::ptr_eq(child, node));
parent.borrow_mut().degree -= 1;
node.borrow_mut().parent = None;
node.borrow_mut().marked = false;
self.root_list.push(Rc::clone(node));
}
fn cascading_cut(&mut self, node: &Rc<RefCell<Node<T>>>) {
if let Some(parent_weak) = &node.borrow().parent
&& let Some(parent) = parent_weak.upgrade()
{
if !node.borrow().marked {
node.borrow_mut().marked = true;
} else {
self.cut(node, &parent);
self.cascading_cut(&parent);
}
}
}
pub fn peek_min(&self) -> Option<T> {
self.min.as_ref().map(|min| min.borrow().key.clone())
}
pub fn is_empty(&self) -> bool {
self.root_list.is_empty()
}
pub fn len(&self) -> usize {
self.node_count
}
pub fn clear(&mut self) {
self.min = None;
self.root_list.clear();
self.node_count = 0;
self.active_nodes.clear();
self.next_id.store(0, AtomicOrdering::SeqCst);
}
}
pub type FibonacciHeap = GenericFibonacciHeap<i32>;
pub type FibonacciHeapI8 = GenericFibonacciHeap<i8>;
pub type FibonacciHeapI16 = GenericFibonacciHeap<i16>;
pub type FibonacciHeapI32 = GenericFibonacciHeap<i32>;
pub type FibonacciHeapI64 = GenericFibonacciHeap<i64>;
pub type FibonacciHeapI128 = GenericFibonacciHeap<i128>;
pub type FibonacciHeapISize = GenericFibonacciHeap<isize>;
pub type FibonacciHeapU8 = GenericFibonacciHeap<u8>;
pub type FibonacciHeapU16 = GenericFibonacciHeap<u16>;
pub type FibonacciHeapU32 = GenericFibonacciHeap<u32>;
pub type FibonacciHeapU64 = GenericFibonacciHeap<u64>;
pub type FibonacciHeapU128 = GenericFibonacciHeap<u128>;
pub type FibonacciHeapUSize = GenericFibonacciHeap<usize>;
pub type FibonacciHeapF32 = GenericFibonacciHeap<f32>;
pub type FibonacciHeapF64 = GenericFibonacciHeap<f64>;
pub type FibonacciHeapChar = GenericFibonacciHeap<char>;
#[cfg(test)]
mod tests {
use rand::RngExt;
use super::*;
#[test]
fn test_basic_operations_i32() {
let mut heap = GenericFibonacciHeap::<i32>::new();
assert!(heap.is_empty());
heap.insert(10).unwrap();
heap.insert(5).unwrap();
assert_eq!(heap.len(), 2);
assert_eq!(heap.extract_min(), Some(5));
assert_eq!(heap.extract_min(), Some(10));
assert!(heap.is_empty());
}
#[test]
fn test_basic_operations_f64() {
let mut heap = GenericFibonacciHeap::<f64>::new();
assert!(heap.is_empty());
heap.insert(10.5).unwrap();
heap.insert(5.2).unwrap();
assert_eq!(heap.len(), 2);
assert_eq!(heap.extract_min(), Some(5.2));
assert_eq!(heap.extract_min(), Some(10.5));
assert!(heap.is_empty());
}
#[test]
fn test_basic_operations_char() {
let mut heap = GenericFibonacciHeap::<char>::new();
assert!(heap.is_empty());
heap.insert('z').unwrap();
heap.insert('a').unwrap();
assert_eq!(heap.len(), 2);
assert_eq!(heap.extract_min(), Some('a'));
assert_eq!(heap.extract_min(), Some('z'));
assert!(heap.is_empty());
}
#[test]
fn test_merge() {
let mut heap1 = GenericFibonacciHeap::new();
heap1.insert(10).unwrap();
heap1.insert(20).unwrap();
let mut heap2 = GenericFibonacciHeap::new();
heap2.insert(5).unwrap();
heap2.insert(15).unwrap();
heap1.merge(heap2);
assert_eq!(heap1.len(), 4);
assert_eq!(heap1.extract_min(), Some(5));
}
#[test]
fn test_decrease_key() {
let mut heap = GenericFibonacciHeap::new();
let node = heap.insert(20).unwrap();
heap.insert(10).unwrap();
assert_eq!(heap.extract_min(), Some(10));
heap.decrease_key(&node, 5).unwrap();
assert_eq!(heap.extract_min(), Some(5));
}
#[test]
fn test_decrease_key_validation() {
let mut heap = GenericFibonacciHeap::new();
let node = heap.insert(10).unwrap();
assert_eq!(heap.decrease_key(&node, 15), Err(HeapError::InvalidKey));
assert!(heap.decrease_key(&node, 5).is_ok());
}
#[test]
fn test_decrease_key_with_nan() {
let mut heap = GenericFibonacciHeap::<f64>::new();
let node = heap.insert(10.0).unwrap();
assert_eq!(
heap.decrease_key(&node, f64::NAN),
Err(HeapError::KeyComparisonError)
);
}
#[test]
fn test_type_aliases() {
let mut heap_i32: FibonacciHeapI32 = FibonacciHeapI32::new();
heap_i32.insert(42).unwrap();
assert_eq!(heap_i32.extract_min(), Some(42));
let mut heap_f64: FibonacciHeapF64 = FibonacciHeapF64::new();
heap_f64.insert(3.14).unwrap();
assert_eq!(heap_f64.extract_min(), Some(3.14));
let mut heap_char: FibonacciHeapChar = FibonacciHeapChar::new();
heap_char.insert('x').unwrap();
assert_eq!(heap_char.extract_min(), Some('x'));
}
#[test]
fn test_backward_compatibility() {
let mut heap: FibonacciHeap = FibonacciHeap::new();
heap.insert(100).unwrap();
heap.insert(50).unwrap();
assert_eq!(heap.extract_min(), Some(50));
assert_eq!(heap.extract_min(), Some(100));
}
#[test]
fn test_triple_zero_four_pops() {
let mut heap = GenericFibonacciHeap::<i32>::new();
heap.insert(0).unwrap();
heap.insert(0).unwrap();
heap.insert(0).unwrap();
assert_eq!(heap.extract_min(), Some(0)); assert_eq!(heap.extract_min(), Some(0)); assert_eq!(heap.extract_min(), Some(0)); assert_eq!(heap.extract_min(), None);
for n in 1..=16 {
let mut h = GenericFibonacciHeap::<i32>::new();
for _ in 0..n { h.insert(0).unwrap(); }
for i in 0..n { assert_eq!(h.extract_min(), Some(0), "pop {} of {}", i+1, n); }
assert_eq!(h.extract_min(), None, "extra pop after {} zeros", n);
assert_eq!(h.len(), 0, "len after draining {} zeros", n);
}
}
#[test]
fn test_consolidate_no_panic_stress() {
let mut rng = rand::rng();
for _ in 0..200 {
let mut heap = GenericFibonacciHeap::<i32>::new();
let n = rng.random_range(10_000..50_000);
for _ in 0..n {
heap.insert(rng.random_range(0..1_000_000)).unwrap();
}
for _ in 0..(n / 2) {
heap.extract_min();
}
for _ in 0..1000 {
if rng.random_bool(0.5) {
heap.insert(rng.random_range(0..1_000_000)).unwrap();
} else {
heap.extract_min();
}
}
assert!(heap.len() <= n + 1000);
}
}
}