use std::sync::{Arc, Mutex};
type NodePtr = Arc<Mutex<Node>>;
#[derive(Clone)]
pub struct Node {
pub key: i32, degree: usize, marked: bool, parent: Option<NodePtr>, children: Vec<NodePtr>, }
impl Node {
pub fn new(key: i32) -> NodePtr {
Arc::new(Mutex::new(Node {
key,
degree: 0,
marked: false,
parent: None,
children: Vec::new(),
}))
}
}
pub struct FibonacciHeap {
min: Option<NodePtr>, pub root_list: Vec<NodePtr>, }
impl Default for FibonacciHeap {
fn default() -> Self {
Self::new()
}
}
impl FibonacciHeap {
pub fn new() -> Self {
FibonacciHeap {
min: None,
root_list: Vec::new(),
}
}
pub fn insert(&mut self, key: i32) -> NodePtr {
let node = Node::new(key);
self.root_list.push(node.clone());
if let Some(ref min) = self.min {
if key < min.lock().unwrap().key {
self.min = Some(node.clone());
}
} else {
self.min = Some(node.clone());
}
node
}
pub fn merge(&mut self, other: &mut FibonacciHeap) {
self.root_list.append(&mut other.root_list);
if let Some(ref other_min) = other.min {
match &self.min {
Some(self_min) if other_min.lock().unwrap().key < self_min.lock().unwrap().key => {
self.min = Some(other_min.clone());
}
None => {
self.min = Some(other_min.clone());
}
_ => {}
}
}
other.root_list.clear();
other.min = None;
}
pub fn extract_min(&mut self) -> Option<i32> {
let min_node = self.min.take()?;
let min_key = min_node.lock().unwrap().key;
let children = std::mem::take(&mut min_node.lock().unwrap().children);
for child in &children {
child.lock().unwrap().parent = None;
self.root_list.push(child.clone());
}
self.root_list.retain(|node| !Arc::ptr_eq(node, &min_node));
if self.root_list.is_empty() {
self.min = None;
} else {
self.consolidate();
}
Some(min_key)
}
fn consolidate(&mut self) {
const MAX_DEGREE: usize = 64;
let mut degrees: [Option<NodePtr>; MAX_DEGREE] = std::array::from_fn(|_| None);
let original_root_list = std::mem::take(&mut self.root_list);
let mut new_min = None;
for node in original_root_list {
let mut current = node;
let mut degree = current.lock().unwrap().degree;
while let Some(existing) = degrees[degree].take() {
let current_key = current.lock().unwrap().key;
let existing_key = existing.lock().unwrap().key;
if existing_key < current_key {
self.link(current.clone(), existing.clone());
current = existing;
} else {
self.link(existing.clone(), current.clone());
}
degree = current.lock().unwrap().degree;
if degree >= MAX_DEGREE {
panic!("Degree exceeded MAX_DEGREE!");
}
}
degrees[degree] = Some(current.clone());
let current_key = current.lock().unwrap().key;
new_min = match new_min {
None => Some(current.clone()),
Some(min) if current_key < min.lock().unwrap().key => Some(current.clone()),
min => min,
};
}
self.root_list = degrees.into_iter().flatten().collect();
self.min = new_min;
}
fn link(&mut self, node: NodePtr, parent: NodePtr) {
{
let mut node_guard = node.lock().unwrap();
node_guard.parent = Some(parent.clone());
node_guard.marked = false;
}
{
let mut parent_guard = parent.lock().unwrap();
parent_guard.children.push(node.clone());
parent_guard.degree += 1;
}
}
pub fn decrease_key(&mut self, node: &NodePtr, new_key: i32) {
let mut node_guard = node.lock().unwrap();
if new_key > node_guard.key {
panic!("New key is greater than current key!");
}
node_guard.key = new_key;
let parent = node_guard.parent.clone();
drop(node_guard);
if let Some(parent_ref) = parent {
if new_key < parent_ref.lock().unwrap().key {
self.cut(node.clone(), parent_ref.clone());
self.cascading_cut(parent_ref);
}
}
if let Some(ref current_min) = self.min {
if new_key < current_min.lock().unwrap().key {
self.min = Some(node.clone());
}
} else {
self.min = Some(node.clone());
}
}
fn cut(&mut self, node: NodePtr, parent: NodePtr) {
let mut parent_guard = parent.lock().unwrap();
parent_guard.children.retain(|child| !Arc::ptr_eq(child, &node));
parent_guard.degree -= 1;
drop(parent_guard);
let mut node_guard = node.lock().unwrap();
self.root_list.push(node.clone());
node_guard.parent = None;
node_guard.marked = false;
}
fn cascading_cut(&mut self, node: NodePtr) {
let parent = node.lock().unwrap().parent.clone();
if let Some(parent_ref) = parent {
let marked = node.lock().unwrap().marked;
if !marked {
node.lock().unwrap().marked = true;
} else {
self.cut(node.clone(), parent_ref.clone());
self.cascading_cut(parent_ref);
}
}
}
pub fn is_empty(&self) -> bool {
self.root_list.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_insert() {
let mut heap = FibonacciHeap::new();
let node = heap.insert(10);
assert_eq!(node.lock().unwrap().key, 10);
assert_eq!(heap.min.unwrap().lock().unwrap().key, 10);
}
#[test]
fn test_extract_min() {
let mut heap = FibonacciHeap::new();
heap.insert(10);
heap.insert(20);
heap.insert(5);
let min = heap.extract_min();
assert_eq!(min, Some(5));
assert_eq!(heap.min.unwrap().lock().unwrap().key, 10);
}
#[test]
fn test_merge() {
let mut heap1 = FibonacciHeap::new();
let mut heap2 = FibonacciHeap::new();
heap1.insert(10);
heap2.insert(5);
heap2.insert(20);
heap1.merge(&mut heap2);
assert_eq!(heap1.extract_min(), Some(5));
}
#[test]
fn test_decrease_key() {
let mut heap = FibonacciHeap::new();
let node = heap.insert(10);
heap.decrease_key(&node, 5);
assert_eq!(heap.min.unwrap().lock().unwrap().key, 5);
}
#[test]
#[should_panic(expected = "New key is greater than current key!")]
fn test_decrease_key_invalid() {
let mut heap = FibonacciHeap::new();
let node = heap.insert(10);
heap.decrease_key(&node, 15);
}
#[test]
fn test_empty_heap() {
let heap = FibonacciHeap::new();
assert!(heap.is_empty());
}
}