forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfibonacci_heap.py
152 lines (126 loc) · 4.04 KB
/
fibonacci_heap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Reference: https://en.wikipedia.org/wiki/Fibonacci_heap
import math
from typing import Optional
class FibonacciTree:
"""
FibonacciTree represents a node in a Fibonacci heap.
Attributes:
key (int): The key value associated with the node.
children (list): A list of child nodes.
order (int): The number of children the node has.
"""
def __init__(self, key: int) -> None:
self.key = key
self.children: list['FibonacciTree'] = []
self.order = 0
def add_at_end(self, child_node: 'FibonacciTree') -> None:
"""
Adds a child node 'child_node' to the end of the children list.
Args:
child_node (FibonacciTree): The child node to add.
"""
self.children.append(child_node)
self.order = self.order + 1
class FibonacciHeap:
"""
FibonacciHeap represents a priority queue data structure with efficient
amortized time complexities for various operations.
Usage:
>>> heap = FibonacciHeap()
>>> heap.insert(5)
>>> heap.insert(3)
>>> heap.insert(7)
>>> heap.get_min()
3
>>> heap.extract_min()
3
>>> heap.get_min()
5
Attributes:
trees (list): A list of FibonacciTree objects.
least (FibonacciTree): A reference to the node with the minimum key.
count (int): The total number of nodes in the heap.
"""
def __init__(self) -> None:
self.trees: list['FibonacciTree'] = []
self.least: Optional['FibonacciTree'] = None
self.count = 0
def insert(self, key: int) -> None:
"""
Inserts a new node with the given key into the Fibonacci heap.
Args:
key (int): The key to insert.
"""
new_tree = FibonacciTree(key)
self.trees.append(new_tree)
if (self.least is None or key < self.least.key):
self.least = new_tree
self.count = self.count + 1
def get_min(self) -> Optional[int]:
"""
Returns the minimum key in the Fibonacci heap.
Returns:
int: The minimum key.
"""
if self.least is None:
return None
return self.least.key
def extract_min(self) -> Optional[int]:
"""
Removes and returns the node with the minimum key from the Fibonacci heap.
Returns:
int: The minimum key.
"""
smallest = self.least
if smallest is not None:
for child in smallest.children:
if child is not None:
self.trees.append(child)
self.trees.remove(smallest)
if self.trees:
self.least = self.trees[0]
self.consolidate()
else:
self.least = None
self.count = self.count - 1
return smallest.key
return None
def consolidate(self) -> None:
"""
Consolidates trees in the Fibonacci heap to maintain the heap's structure.
"""
aux = (floor_log2(self.count) + 1) * [None]
while self.trees:
x = self.trees[0]
order = x.order
self.trees.remove(x)
while aux[order] is not None:
y = aux[order]
if x.key > y.key:
x, y = y, x
x.add_at_end(y)
aux[order] = None
order = order + 1
aux[order] = x
self.least = None
for k in aux:
if k is not None:
self.trees.append(k)
if (self.least is None or k.key < self.least.key):
self.least = k
def floor_log2(x: int) -> int:
"""
Computes the floor of the base-2 logarithm of 'x'.
Args:
x (int): The input number.
Returns:
int: The floor of the base-2 logarithm of 'x'.
"""
return math.floor(math.log2(x)) if x > 0 else 0
# Doctest for floor_log2
if __name__ == "__main__":
import doctest
doctest.testmod()
if __name__ == "__main__":
import doctest
doctest.testmod()