Skip to content

Added an implementation of fibonacci heap. #12375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
178 changes: 178 additions & 0 deletions data_structures/heap/fibonacci_heap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import math


class FibonacciHeapNode:
def __init__(self, key, value=None):
self.key = key
self.value = value
self.degree = 0
self.parent = None
self.child = None
self.mark = False
self.next = self
self.prev = self

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

if not self.child:
self.child = node
else:
node.prev = self.child
node.next = self.child.next
self.child.next.prev = node
self.child.next = node
node.parent = self
self.degree += 1

def remove_child(self, node):
if node.next == node: # Single child
self.child = None
elif self.child == node:
self.child = node.next
node.prev.next = node.next
node.next.prev = node.prev
node.parent = None
self.degree -= 1


class FibonacciHeap:
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.total_nodes = 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 self.min_node is None

def insert(self, key, value=None):
node = FibonacciHeapNode(key, value)
self._merge_with_root_list(node)
if not self.min_node or node.key < self.min_node.key:
self.min_node = node
self.total_nodes += 1
return node

def find_min(self):
return self.min_node

def union(self, other_heap):
if not other_heap.min_node:
return self
if not self.min_node:
self.min_node = other_heap.min_node
else:
self._merge_with_root_list(other_heap.min_node)
if other_heap.min_node.key < self.min_node.key:
self.min_node = other_heap.min_node
self.total_nodes += other_heap.total_nodes

def extract_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: extract_min. If the function does not return a value, please provide the type hint as: def function() -> None:

z = self.min_node
if z:
if z.child:
children = list(self._iterate(z.child))
for child in children:
self._merge_with_root_list(child)
child.parent = None
self._remove_from_root_list(z)
if z == z.next:
self.min_node = None
else:
self.min_node = z.next
self._consolidate()
self.total_nodes -= 1
return z

def decrease_key(self, x, new_key):
if new_key > x.key:
raise ValueError("New key is greater than current key")
x.key = new_key
y = x.parent
if y and x.key < y.key:
self._cut(x, y)
self._cascading_cut(y)
if x.key < self.min_node.key:
self.min_node = x

def delete(self, x):
self.decrease_key(x, -math.inf)
self.extract_min()

def _cut(self, x, y):
y.remove_child(x)
self._merge_with_root_list(x)
x.mark = False

def _cascading_cut(self, y):
if z := y.parent:
if not y.mark:
y.mark = True
else:
self._cut(y, z)
self._cascading_cut(z)

def _merge_with_root_list(self, node):
if not self.min_node:
self.min_node = node
else:
node.prev = self.min_node
node.next = self.min_node.next
self.min_node.next.prev = node
self.min_node.next = node

def _remove_from_root_list(self, node):
if node.next == node:
self.min_node = None
else:
node.prev.next = node.next
node.next.prev = node.prev

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:

array_size = int(math.log(self.total_nodes) * 2) + 1
array = [None] * array_size
nodes = list(self._iterate(self.min_node))
for w in nodes:
x = w
d = x.degree
while array[d]:
y = array[d]
if x.key > y.key:
x, y = y, x
self._link(y, x)
array[d] = None
d += 1
array[d] = x
self.min_node = None
for i in range(array_size):
if array[i]:
if not self.min_node:
self.min_node = array[i]
else:
self._merge_with_root_list(array[i])
if array[i].key < self.min_node.key:
self.min_node = array[i]

def _link(self, y, x):
self._remove_from_root_list(y)
x.add_child(y)
y.mark = False

def _iterate(self, start):
node = start
while True:
yield node
node = node.next
if node == start:
break


# Example usage
if __name__ == "__main__":
fh = FibonacciHeap()
n1 = fh.insert(10, "value1")
n2 = fh.insert(2, "value2")
n3 = fh.insert(15, "value3")

print("Min:", fh.find_min().key) # Output: 2
fh.decrease_key(n3, 1)
print("Min after decrease key:", fh.find_min().key) # Output: 1
fh.extract_min()
print("Min after extract:", fh.find_min().key) # Output: 2