forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfibonacci_heap.py
157 lines (130 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
153
154
155
156
157
# Reference: https://en.wikipedia.org/wiki/Fibonacci_heap
import math
from typing import List
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
# Doctest for add_at_end
if __name__ == "__main__":
import doctest
doctest.testmod()
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 = 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)->int:
"""
Returns the minimum key in the Fibonacci heap.
Returns:
int: The minimum key.
"""
if self.least is None:
return -1
return self.least.key
def extract_min(self)->int:
"""
Removes and returns the node with the minimum key from the Fibonacci heap.
Returns:
int: The minimum key.
"""
smallest = None
if self.least is not None:
smallest = self.least
for child in smallest.children:
self.trees.append(child)
self.trees.remove(smallest)
if self.trees == []:
self.least = None
else:
self.least = self.trees[0]
self.consolidate()
self.count = self.count - 1
return smallest.key
return -1
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.frexp(x)[1] - 1
# Doctest for floor_log2
if __name__ == "__main__":
import doctest
doctest.testmod()
if __name__ == "__main__":
import doctest
doctest.testmod()