Skip to content
Closed
256 changes: 256 additions & 0 deletions data_structures/heap/fibonacci_heap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
"""
Fibonacci Heap
A more efficient priority queue implementation that provides amortized time bounds
that are better than those of the binary and binomial heaps.

Operations supported:
- Insert: O(1) amortized
- Find minimum: O(1)
- Delete minimum: O(log n) amortized
- Decrease key: O(1) amortized
- Merge: O(1)
"""


class Node:
"""
Node in a Fibonacci heap containing:
- value
- parent, child, and sibling links
- degree (number of children)
- mark (whether the node has lost a child since
becoming a child of its current parent)
"""

def __init__(self, val):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __init__. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: val

self.val = val
self.parent = None
self.child = None
self.left = self
self.right = self
self.degree = 0
self.mark = False

def add_sibling(self, node):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file data_structures/heap/fibonacci_heap.py, please provide doctest for the function add_sibling

Please provide return type hint for the function: add_sibling. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node

"""Add node as a sibling"""
node.left = self
node.right = self.right
self.right.left = node
self.right = node

def add_child(self, node):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file data_structures/heap/fibonacci_heap.py, please provide doctest for the function add_child

Please provide return type hint for the function: add_child. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node

"""Add node as a child"""
node.parent = self
if not self.child:
self.child = node
else:
self.child.add_sibling(node)
self.degree += 1

def remove(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is no test file in this pull request nor any test function or class in the file data_structures/heap/fibonacci_heap.py, please provide doctest for the function remove

Please provide return type hint for the function: remove. If the function does not return a value, please provide the type hint as: def function() -> None:

"""Remove this node from its sibling list"""
self.left.right = self.right
self.right.left = self.left


class FibonacciHeap:
"""
Min-oriented Fibonacci heap implementation.

Example:
>>> heap = FibonacciHeap()
>>> heap.insert(3)
>>> heap.insert(2)
>>> heap.insert(15)
>>> heap.peek()
2
>>> heap.delete_min()
2
>>> heap.peek()
3
"""

def __init__(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __init__. If the function does not return a value, please provide the type hint as: def function() -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __init__. If the function does not return a value, please provide the type hint as: def function() -> None:

self.min_node = None
self.size = 0

def is_empty(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: is_empty. If the function does not return a value, please provide the type hint as: def function() -> None:

"""Return True if heap is empty"""
return self.min_node is None

def insert(self, val):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: insert. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: val

"""Insert a new key into the heap"""
node = Node(val)
if not self.min_node:
self.min_node = node
else:
self.min_node.add_sibling(node)
if node.val < self.min_node.val:
self.min_node = node
self.size += 1
return node

def peek(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: peek. If the function does not return a value, please provide the type hint as: def function() -> None:

"""Return minimum value without removing it"""
if not self.min_node:
raise IndexError("Heap is empty")
return self.min_node.val

def merge_heaps(self, other):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: merge_heaps. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: other

"""Merge another Fibonacci heap with this one"""
if not other.min_node:
return
if not self.min_node:
self.min_node = other.min_node
else:
# Merge root lists
self.min_node.right.left = other.min_node.left
other.min_node.left.right = self.min_node.right
self.min_node.right = other.min_node
other.min_node.left = self.min_node

if other.min_node.val < self.min_node.val:
self.min_node = other.min_node

self.size += other.size

def __link_trees(self, node1, node2):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __link_trees. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node1

Please provide type hint for the parameter: node2

"""Link two trees of same degree"""
node1.remove()
if node2.child:
node2.child.add_sibling(node1)
else:
node2.child = node1
node1.parent = node2
node2.degree += 1
node1.mark = False

def delete_min(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: delete_min. If the function does not return a value, please provide the type hint as: def function() -> None:

"""Remove and return the minimum value"""
if not self.min_node:
raise IndexError("Heap is empty")

min_val = self.min_node.val

# Add all children to root list
if self.min_node.child:
curr = self.min_node.child
while True:
next_node = curr.right
curr.parent = None
curr.mark = False
self.min_node.add_sibling(curr)
if curr.right == self.min_node.child:
break
curr = next_node

# Remove minimum node
if self.min_node.right == self.min_node:
self.min_node = None
else:
self.min_node.remove()
self.min_node = self.min_node.right
self.__consolidate()

self.size -= 1
return min_val

def __consolidate(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __consolidate. If the function does not return a value, please provide the type hint as: def function() -> None:

"""Consolidate trees after delete_min"""
max_degree = int(self.size**0.5) + 1
degree_table = [None] * max_degree

# Collect all roots
roots = []
curr = self.min_node
while True:
roots.append(curr)
curr = curr.right
if curr == self.min_node:
break

# Consolidate trees
for root in roots:
degree = root.degree
while degree_table[degree]:
other = degree_table[degree]
if root.val > other.val:
root, other = other, root
self.__link_trees(other, root)
degree_table[degree] = None
degree += 1
degree_table[degree] = root

# Find new minimum
self.min_node = None
for degree in range(max_degree):
if degree_table[degree]:
if not self.min_node:
self.min_node = degree_table[degree]
self.min_node.left = self.min_node
self.min_node.right = self.min_node
else:
self.min_node.add_sibling(degree_table[degree])
if degree_table[degree].val < self.min_node.val:
self.min_node = degree_table[degree]

def decrease_key(self, node, new_val):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: decrease_key. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node

Please provide type hint for the parameter: new_val

"""Decrease the value of a node"""
if new_val > node.val:
raise ValueError("New value is greater than current value")

node.val = new_val
parent = node.parent

if parent and node.val < parent.val:
self.__cut(node, parent)
self.__cascading_cut(parent)

if node.val < self.min_node.val:
self.min_node = node

def __cut(self, node, parent):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __cut. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node

Please provide type hint for the parameter: parent

"""Cut a node from its parent"""
parent.degree -= 1
if parent.child == node:
parent.child = node.right if node.right != node else None
node.remove()
node.left = node
node.right = node
node.parent = None
node.mark = False
self.min_node.add_sibling(node)

def __cascading_cut(self, node):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __cascading_cut. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node

"""Perform cascading cut operation"""
if parent := node.parent:
if not node.mark:
node.mark = True
else:
self.__cut(node, parent)
self.__cascading_cut(parent)

def __str__(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: __str__. If the function does not return a value, please provide the type hint as: def function() -> None:

"""String representation of the heap"""
if not self.min_node:
return "Empty heap"

def print_tree(node, level=0):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide return type hint for the function: print_tree. If the function does not return a value, please provide the type hint as: def function() -> None:

Please provide type hint for the parameter: node

Please provide type hint for the parameter: level

result = []
curr = node
while True:
result.append("-" * level + str(curr.val))
if curr.child:
result.extend(print_tree(curr.child, level + 1))
curr = curr.right
if curr == node:
break
return result

return "\n".join(print_tree(self.min_node))


if __name__ == "__main__":
import doctest

doctest.testmod()
Loading