mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-27 15:01:08 +00:00
Merge 144030aed1
into f3f32ae3ca
This commit is contained in:
commit
bed1210960
178
data_structures/heap/fibonacci_heap.py
Normal file
178
data_structures/heap/fibonacci_heap.py
Normal file
|
@ -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):
|
||||
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):
|
||||
self.min_node = None
|
||||
self.total_nodes = 0
|
||||
|
||||
def is_empty(self):
|
||||
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):
|
||||
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):
|
||||
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
|
Loading…
Reference in New Issue
Block a user