A Fibonacci Heap is a data structure that supports efficient operations for priority queues, such as inserting a node, finding the minimum, decreasing a key, and deleting a node. These operations provide amortized time complexities that are significantly better than many traditional heap structures, making Fibonacci heaps useful in algorithms like Dijkstra’s shortest path algorithm and Prim’s minimum spanning tree algorithm.
Before diving into the operations, let's refresh some basic concepts about Fibonacci heaps:
Fibonacci heaps support the following operations:
The Decrease Key operation reduces the value of a key of a specific node in the heap. In a Fibonacci heap, this operation is critical because it helps maintain the heap structure while ensuring that the heap property is not violated.
The Decrease Key operation works as follows:
class FibonacciHeapNode:
def __init__(self, key):
self.key = key
self.degree = 0
self.parent = None
self.child = None
self.mark = False
self.next = None
self.prev = None
class FibonacciHeap:
def __init__(self):
self.min_node = None
self.num_nodes = 0
def decrease_key(self, node, new_key):
if new_key > node.key:
raise ValueError("New key is greater than the current key")
node.key = new_key
parent = node.parent
if parent and node.key < parent.key:
self.cut(node, parent)
self.cascading_cut(parent)
if node.key < self.min_node.key:
self.min_node = node
def cut(self, node, parent):
# Remove node from its parent's child list
if node == node.next:
parent.child = None
else:
node.prev.next = node.next
node.next.prev = node.prev
parent.degree -= 1
# Add node to the root list
node.next = self.min_node
node.prev = self.min_node.prev
self.min_node.prev.next = node
self.min_node.prev = node
node.parent = None
node.mark = False
def cascading_cut(self, parent):
grandparent = parent.parent
if grandparent:
if not parent.mark:
parent.mark = True
else:
self.cut(parent, grandparent)
self.cascading_cut(grandparent)
In this code:
The Delete Node operation removes a node from the Fibonacci heap. This operation is often implemented by first decreasing the key of the node to be deleted to negative infinity (or a very small number) and then performing an Extract Min operation. By making the node the minimum, it will be extracted, thus removing it from the heap.
This approach leverages the already existing Decrease Key and Extract Min operations for efficiency.
def delete_node(self, node):
# Decrease the key of the node to negative infinity
self.decrease_key(node, float('-inf'))
# Extract the minimum, which will remove the node
self.extract_min()
def extract_min(self):
min_node = self.min_node
if min_node:
# Remove the minimum node from the root list
if min_node.next == min_node:
self.min_node = None
else:
min_node.prev.next = min_node.next
min_node.next.prev = min_node.prev
self.min_node = min_node.next
# Move the children of min_node to the root list
children = []
child = min_node.child
while child:
children.append(child)
child = child.next
for child in children:
self.add_to_root_list(child)
self.num_nodes -= 1
return min_node
In this code:
Both Decrease Key and Delete Node operations in Fibonacci heaps have efficient amortized time complexities:
These operations make Fibonacci heaps especially efficient for algorithms that require frequent priority updates, such as Dijkstra's shortest path algorithm.