-
-
Notifications
You must be signed in to change notification settings - Fork 46.2k
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
Fibonacci Heap Implementation #12397
base: master
Are you sure you want to change the base?
Changes from all commits
a71d17a
a21a624
2e35261
fe95a31
369994d
ea5a187
a92936b
071ce71
bd943b0
a1291fd
c4516d1
144030a
502953a
7b987a0
660976f
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,382 @@ | ||
""" | ||
Fibonacci Heap Implementation in Python. | ||
|
||
This module provides an implementation of a Fibonacci Heap, a data structure | ||
that supports a priority queue with efficient operations. | ||
Referenced from: https://en.wikipedia.org/wiki/Fibonacci_heap | ||
|
||
Classes: | ||
- FibonacciHeapNode: Represents a node in the Fibonacci Heap. | ||
- FibonacciHeap: Represents the Fibonacci Heap itself. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> n1 = fh.insert(10, "value1") | ||
>>> n2 = fh.insert(2, "value2") | ||
>>> n3 = fh.insert(15, "value3") | ||
>>> fh.find_min().key | ||
2 | ||
>>> fh.decrease_key(n3, 1) | ||
>>> fh.find_min().key | ||
1 | ||
>>> fh.extract_min().key | ||
1 | ||
>>> fh.find_min().key | ||
2 | ||
""" | ||
|
||
import math | ||
|
||
|
||
class FibonacciHeapNode: | ||
""" | ||
Represents a node in the Fibonacci Heap. | ||
|
||
Attributes: | ||
key (any): The key of the node. | ||
value (any): The value associated with the key. | ||
degree (int): The number of children of this node. | ||
parent (FibonacciHeapNode): The parent of this node. | ||
child (FibonacciHeapNode): The first child of this node. | ||
mark (bool): Whether this node has | ||
lost a child since it became a child of another node. | ||
next (FibonacciHeapNode): The next sibling in the circular doubly-linked list. | ||
prev (FibonacciHeapNode): The previous sibling | ||
in the circular doubly-linked list. | ||
""" | ||
|
||
def __init__(self, key, value=None): | ||
""" | ||
Initializes a new Fibonacci Heap Node. | ||
|
||
Args: | ||
key (any): The key of the node. | ||
value (any, optional): The value associated with the key. Defaults to 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): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Adds a child node to this node. | ||
|
||
Args: | ||
node (FibonacciHeapNode): The child node to be added. | ||
""" | ||
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): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Removes a child node from this node. | ||
|
||
Args: | ||
node (FibonacciHeapNode): The child node to be removed. | ||
""" | ||
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: | ||
""" | ||
Represents a Fibonacci Heap. | ||
|
||
Attributes: | ||
min_node (FibonacciHeapNode): The node with the minimum key. | ||
total_nodes (int): The total number of nodes in the heap. | ||
""" | ||
|
||
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: |
||
""" | ||
Initializes an empty Fibonacci Heap. | ||
""" | ||
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: |
||
""" | ||
Checks if the heap is empty. | ||
|
||
Returns: | ||
bool: True if the heap is empty, False otherwise. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> fh.is_empty() | ||
True | ||
>>> n1 = fh.insert(5) | ||
>>> fh.is_empty() | ||
False | ||
""" | ||
return self.min_node is None | ||
|
||
def insert(self, key, value=None): | ||
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: Please provide type hint for the parameter: Please provide type hint for the parameter: |
||
""" | ||
Inserts a new node into the heap. | ||
|
||
Args: | ||
key (any): The key of the new node. | ||
value (any, optional): The value associated with the key. Defaults to None. | ||
|
||
Returns: | ||
FibonacciHeapNode: The newly inserted node. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> node = fh.insert(5, "value") | ||
>>> node.key | ||
5 | ||
""" | ||
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): | ||
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: |
||
""" | ||
Finds the node with the minimum key. | ||
|
||
Returns: | ||
FibonacciHeapNode: The node with the minimum key. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> n1 = fh.insert(10) | ||
>>> n2 = fh.insert(2) | ||
>>> fh.find_min().key | ||
2 | ||
""" | ||
return self.min_node | ||
|
||
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: |
||
""" | ||
Removes and returns the node with the minimum key. | ||
|
||
Returns: | ||
FibonacciHeapNode: The node with the minimum key. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> n1 = fh.insert(10) | ||
>>> n2 = fh.insert(2) | ||
>>> fh.extract_min().key | ||
2 | ||
""" | ||
temp_min_node = self.min_node | ||
if temp_min_node: | ||
if temp_min_node.child: | ||
children = list(self._iterate(temp_min_node.child)) | ||
for child in children: | ||
self._merge_with_root_list(child) | ||
child.parent = None | ||
self._remove_from_root_list(temp_min_node) | ||
if temp_min_node == temp_min_node.next: | ||
self.min_node = None | ||
else: | ||
self.min_node = temp_min_node.next | ||
self._consolidate() | ||
self.total_nodes -= 1 | ||
return temp_min_node | ||
|
||
def decrease_key(self, node, new_key): | ||
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: Please provide type hint for the parameter: Please provide type hint for the parameter: |
||
""" | ||
Decreases the key of a given node. | ||
|
||
Args: | ||
node (FibonacciHeapNode): The node to decrease the key for. | ||
new_key (any): The new key value. | ||
|
||
Raises: | ||
ValueError: If the new key is greater than the current key. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> node = fh.insert(10) | ||
>>> fh.decrease_key(node, 5) | ||
>>> fh.find_min().key | ||
5 | ||
""" | ||
if new_key > node.key: | ||
raise ValueError("New key is greater than current key") | ||
node.key = new_key | ||
temp_parent = node.parent | ||
if temp_parent and node.key < temp_parent.key: | ||
self._cut(node, temp_parent) | ||
self._cascading_cut(temp_parent) | ||
if node.key < self.min_node.key: | ||
self.min_node = node | ||
|
||
def delete(self, x): | ||
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: Please provide type hint for the parameter: Please provide descriptive name for the parameter: |
||
""" | ||
Deletes a given node from the heap. | ||
|
||
Args: | ||
x (FibonacciHeapNode): The node to be deleted. | ||
|
||
Examples: | ||
>>> fh = FibonacciHeap() | ||
>>> node = fh.insert(10) | ||
>>> fh.delete(node) | ||
>>> fh.is_empty() | ||
True | ||
""" | ||
self.decrease_key(x, -math.inf) | ||
self.extract_min() | ||
|
||
def union(self, other_heap): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Merges another Fibonacci Heap into this heap. | ||
|
||
Args: | ||
other_heap (FibonacciHeap): The other Fibonacci Heap to be merged. | ||
|
||
Examples: | ||
>>> fh1 = FibonacciHeap() | ||
>>> fh2 = FibonacciHeap() | ||
>>> n1 = fh1.insert(10) | ||
>>> n2 = fh2.insert(5) | ||
>>> fh1.union(fh2) | ||
>>> fh1.find_min().key | ||
5 | ||
""" | ||
if not other_heap.min_node: | ||
return | ||
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 _merge_with_root_list(self, node): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Merges a node into the root list. | ||
|
||
Args: | ||
node (FibonacciHeapNode): The node to be merged. | ||
""" | ||
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): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Removes a node from the root list. | ||
|
||
Args: | ||
node (FibonacciHeapNode): The node to be removed. | ||
""" | ||
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: |
||
""" | ||
Consolidates the heap by combining trees of the same degree. | ||
""" | ||
array_size = int(math.log(self.total_nodes) * 2) + 1 | ||
array = [None] * array_size | ||
nodes = list(self._iterate(self.min_node)) | ||
for node in nodes: | ||
temp_node = node | ||
degree = temp_node.degree | ||
while array[degree]: | ||
array_node = array[degree] | ||
if temp_node.key > array_node.key: | ||
temp_node, array_node = array_node, temp_node | ||
self._link(array_node, temp_node) | ||
array[degree] = None | ||
degree += 1 | ||
array[degree] = temp_node | ||
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, node_to_link, node_to_parent): | ||
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: Please provide type hint for the parameter: Please provide type hint for the parameter: |
||
""" | ||
Links two nodes by making one a child of the other. | ||
|
||
Args: | ||
node_to_link (FibonacciHeapNode): The node to be linked as a child. | ||
node_to_parent (FibonacciHeapNode): The node to be the parent. | ||
""" | ||
self._remove_from_root_list(node_to_link) | ||
node_to_parent.add_child(node_to_link) | ||
node_to_link.mark = False | ||
|
||
def _cut(self, node_to_cut, parent_node): | ||
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: Please provide type hint for the parameter: Please provide type hint for the parameter: |
||
""" | ||
Cuts a node from its parent and adds it to the root list. | ||
|
||
Args: | ||
node_to_cut (FibonacciHeapNode): The node to be cut. | ||
parent_node (FibonacciHeapNode): The parent node. | ||
""" | ||
parent_node.remove_child(node_to_cut) | ||
self._merge_with_root_list(node_to_cut) | ||
node_to_cut.mark = False | ||
|
||
def _cascading_cut(self, node_to_cut): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Performs a cascading cut operation. | ||
|
||
Args: | ||
node_to_cut (FibonacciHeapNode): The node to be cut recursively. | ||
""" | ||
if temp_parent := node_to_cut.parent: | ||
if not node_to_cut.mark: | ||
node_to_cut.mark = True | ||
else: | ||
self._cut(node_to_cut, temp_parent) | ||
self._cascading_cut(temp_parent) | ||
|
||
def _iterate(self, start): | ||
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: Please provide type hint for the parameter: |
||
""" | ||
Iterates through a circular doubly linked list starting at a given node. | ||
|
||
Args: | ||
start (FibonacciHeapNode): The starting node. | ||
|
||
Yields: | ||
FibonacciHeapNode: The next node in the list. | ||
""" | ||
node = start | ||
while True: | ||
yield node | ||
node = node.next | ||
if node == start: | ||
break |
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.
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:
Please provide type hint for the parameter:
key
Please provide type hint for the parameter:
value