use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(PartialEq, Clone)]
pub struct Node {
pub key: i32, degree: usize, marked: bool, parent: Option<Rc<RefCell<Node>>>, children: Vec<Rc<RefCell<Node>>>, }
impl Node {
pub fn new(key: i32) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Node {
key,
degree: 0,
marked: false,
parent: None,
children: Vec::new(),
}))
}
}
pub struct FibonacciHeap {
min: Option<Rc<RefCell<Node>>>, pub root_list: Vec<Rc<RefCell<Node>>>, node_map: HashMap<i32, Rc<RefCell<Node>>>, }
impl Default for FibonacciHeap {
fn default() -> Self {
Self::new()
}
}
impl FibonacciHeap {
pub fn new() -> Self {
FibonacciHeap {
min: None,
root_list: Vec::new(),
node_map: HashMap::new(),
}
}
pub fn insert(&mut self, key: i32) -> Rc<RefCell<Node>> {
let node = Node::new(key);
self.root_list.push(node.clone());
self.node_map.insert(key, node.clone());
if let Some(ref mut min) = self.min {
if key < min.borrow().key {
self.min = Some(node.clone());
}
} else {
self.min = Some(node.clone());
}
node
}
pub fn merge(&mut self, other: &mut FibonacciHeap) {
if let Some(ref min_node) = other.min {
self.root_list.push(min_node.clone());
if let Some(ref mut min) = self.min {
if min_node.borrow().key < min.borrow().key {
self.min = Some(min_node.clone());
}
} else {
self.min = Some(min_node.clone());
}
}
self.root_list.append(&mut other.root_list);
self.node_map.extend(other.node_map.drain());
other.root_list.clear();
other.node_map.clear();
}
pub fn extract_min(&mut self) -> Option<i32> {
let min_node = self.min.take();
if let Some(min_node_ref) = min_node {
let min_key = min_node_ref.borrow().key;
let children = std::mem::take(&mut min_node_ref.borrow_mut().children);
for child in &children {
child.borrow_mut().parent = None;
self.root_list.push(child.clone());
}
self.root_list
.retain(|node| !Rc::ptr_eq(node, &min_node_ref));
if self.root_list.is_empty() {
self.min = None;
} else {
self.consolidate();
}
Some(min_key)
} else {
None
}
}
fn consolidate(&mut self) {
let mut degrees: Vec<Option<Rc<RefCell<Node>>>> = Vec::new();
let original_root_list = std::mem::take(&mut self.root_list);
for node in original_root_list {
let mut current = node;
let mut degree = current.borrow().degree;
loop {
while degree >= degrees.len() {
degrees.push(None);
}
if let Some(existing_node) = degrees[degree].take() {
if existing_node.borrow().key < current.borrow().key {
self.link(current.clone(), existing_node.clone());
current = existing_node;
} else {
self.link(existing_node.clone(), current.clone());
}
degree = current.borrow().degree;
} else {
degrees[degree] = Some(current.clone());
break;
}
}
}
self.root_list = degrees.into_iter().flatten().collect();
self.min = self.root_list.iter().min_by_key(|node| node.borrow().key).cloned();
}
fn link(&mut self, node: Rc<RefCell<Node>>, parent: Rc<RefCell<Node>>) {
node.borrow_mut().parent = Some(parent.clone());
parent.borrow_mut().children.push(node.clone());
parent.borrow_mut().degree += 1;
node.borrow_mut().marked = false;
}
pub fn decrease_key(&mut self, node_key: i32, new_key: i32) {
let node = match self.node_map.get(&node_key) {
Some(rc) => rc.clone(),
None => return,
};
{
let node_borrowed = node.borrow();
if new_key > node_borrowed.key {
panic!("New key is greater than current key!");
}
}
let parent = {
let mut node_borrowed = node.borrow_mut();
node_borrowed.key = new_key;
node_borrowed.parent.clone()
};
if let Some(parent_ref) = parent {
if new_key < parent_ref.borrow().key {
self.cut(node.clone(), parent_ref.clone());
self.cascading_cut(parent_ref);
}
}
self.node_map.remove(&node_key);
self.node_map.insert(new_key, node.clone());
if let Some(ref current_min) = self.min {
if new_key < current_min.borrow().key {
self.min = Some(node);
}
} else {
self.min = Some(node);
}
}
fn cut(&mut self, node: Rc<RefCell<Node>>, parent: Rc<RefCell<Node>>) {
let mut parent_borrowed = parent.borrow_mut();
parent_borrowed
.children
.retain(|child| !Rc::ptr_eq(child, &node));
parent_borrowed.degree -= 1;
self.root_list.push(node.clone());
node.borrow_mut().parent = None;
node.borrow_mut().marked = false;
}
fn cascading_cut(&mut self, node: Rc<RefCell<Node>>) {
let parent = node.borrow().parent.as_ref().map(|p| p.clone());
if let Some(parent_ref) = parent {
if !node.borrow().marked {
node.borrow_mut().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.borrow().key, 10);
assert_eq!(heap.min.unwrap().borrow().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().borrow().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(10, 5);
assert_eq!(heap.min.unwrap().borrow().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(10, 15);
}
#[test]
fn test_empty_heap() {
let heap = FibonacciHeap::new();
assert!(heap.is_empty());
}
#[test]
fn test_multiple_extracts() {
let mut heap = FibonacciHeap::new();
heap.insert(10);
heap.insert(5);
heap.insert(20);
println!(
"Inserted 20, root list: {:?}",
heap.root_list
.iter()
.map(|n| n.borrow().key)
.collect::<Vec<_>>()
);
assert_eq!(heap.extract_min(), Some(5));
assert_eq!(heap.extract_min(), Some(10));
assert_eq!(heap.extract_min(), Some(20));
assert_eq!(heap.extract_min(), None);
}
#[test]
fn test_link() {
let mut heap = FibonacciHeap::new();
let parent = Node::new(10);
let child = Node::new(5);
heap.link(child.clone(), parent.clone());
assert_eq!(parent.borrow().degree, 1);
assert_eq!(parent.borrow().children.len(), 1);
assert!(Rc::ptr_eq(&parent.borrow().children[0], &child));
assert!(child.borrow().parent.as_ref().is_some());
assert!(Rc::ptr_eq(
child.borrow().parent.as_ref().unwrap(),
&parent
));
assert!(!child.borrow().marked);
}
#[test]
fn test_cut() {
let mut heap = FibonacciHeap::new();
let parent = Node::new(10);
let child = Node::new(5);
parent.borrow_mut().children.push(child.clone());
parent.borrow_mut().degree = 1;
child.borrow_mut().parent = Some(parent.clone());
child.borrow_mut().marked = true;
heap.cut(child.clone(), parent.clone());
assert_eq!(parent.borrow().degree, 0);
assert!(parent.borrow().children.is_empty());
assert!(child.borrow().parent.is_none());
assert!(!child.borrow().marked);
assert!(heap.root_list.contains(&child));
}
#[test]
fn test_cascading_cut() {
let mut heap = FibonacciHeap::new();
let root = Node::new(30);
let grandparent = Node::new(20);
let parent = Node::new(15);
let child = Node::new(5);
heap.root_list.push(root.clone());
root.borrow_mut().children.push(grandparent.clone());
root.borrow_mut().degree = 1;
grandparent.borrow_mut().parent = Some(root.clone());
grandparent.borrow_mut().children.push(parent.clone());
grandparent.borrow_mut().degree = 1;
parent.borrow_mut().parent = Some(grandparent.clone());
parent.borrow_mut().children.push(child.clone());
parent.borrow_mut().degree = 1;
child.borrow_mut().parent = Some(parent.clone());
parent.borrow_mut().marked = true;
heap.cut(child.clone(), parent.clone());
heap.cascading_cut(parent.clone());
assert!(heap.root_list.contains(&parent));
assert!(parent.borrow().parent.is_none());
assert_eq!(grandparent.borrow().degree, 0);
assert!(grandparent.borrow().children.is_empty());
assert!(grandparent.borrow().marked);
assert_eq!(root.borrow().degree, 1);
}
}