-
-
Notifications
You must be signed in to change notification settings - Fork 46.8k
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
Changes from all commits
a71d17a
a21a624
2e35261
fe95a31
369994d
ea5a187
a92936b
071ce71
bd943b0
a1291fd
c4516d1
144030a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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): | ||
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): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide return type hint for the function: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide return type hint for the function: |
||
self.min_node = None | ||
self.total_nodes = 0 | ||
|
||
def is_empty(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide return type hint for the function: |
||
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): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide return type hint for the function: |
||
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): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please provide return type hint for the function: |
||
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 |
There was a problem hiding this comment.
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 functionadd_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