Skip to content

Fibonacci Heap Implementation #12397

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

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added tests and docstrings to fibonacci_heap.py
  • Loading branch information
mcawezome committed Nov 18, 2024
commit a92936bd01ca5290f8a1ff78429bfd61a90c0f65
164 changes: 135 additions & 29 deletions data_structures/heap/fibonacci_heap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Fibonacci Heap
A more efficient priority queue implementation that provides amortized time bounds
that are better than those of the binary and binomial heaps.
reference: https://en.wikipedia.org/wiki/Fibonacci_heap

Operations supported:
- Insert: O(1) amortized
Expand All @@ -11,17 +12,22 @@
- Merge: O(1)
"""


class Node:
"""
Node in a Fibonacci heap containing:
- value
- parent, child, and sibling links
- degree (number of children)
- mark (whether the node has lost a child since
becoming a child of its current parent)
A node in a Fibonacci heap.

Args:
val: The value stored in the node.

Attributes:
val: The value stored in the node.
parent: Reference to parent node.
child: Reference to one child node.
left: Reference to left sibling.
right: Reference to right sibling.
degree: Number of children.
mark: Boolean indicating if node has lost a child.
"""

def __init__(self, val):
self.val = val
self.parent = None
Expand All @@ -32,14 +38,24 @@
self.mark = False

def add_sibling(self, node):
"""Add node as a sibling"""
"""
Adds a node as a sibling to the current node.

Args:
node: The node to add as a sibling.
"""
node.left = self
node.right = self.right
self.right.left = node
self.right = node

def add_child(self, node):

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: 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

"""Add node as a child"""
"""
Adds a node as a child of the current node.

Args:
node: The node to add as a child.
"""
node.parent = self
if not self.child:
self.child = node
Expand All @@ -48,38 +64,65 @@
self.degree += 1

def remove(self):
"""Remove this node from its sibling list"""
"""Removes this node from its sibling list."""
self.left.right = self.right
self.right.left = self.left


class FibonacciHeap:
"""
Min-oriented Fibonacci heap implementation.
A Fibonacci heap implementation providing
amortized efficient priority queue operations.

This implementation provides the following time complexities:
- Insert: O(1) amortized
- Find minimum: O(1)
- Delete minimum: O(log n) amortized
- Decrease key: O(1) amortized
- Merge: O(1)

Example:
>>> heap = FibonacciHeap()
>>> heap.insert(3)
>>> heap.insert(2)
>>> heap.insert(15)
>>> node1 = heap.insert(3)
>>> node2 = heap.insert(2)
>>> node3 = heap.insert(15)
>>> heap.peek()
2
>>> heap.delete_min()
2
>>> heap.peek()
3
>>> other_heap = FibonacciHeap()
>>> node4 = other_heap.insert(1)
>>> heap.merge_heaps(other_heap)
>>> heap.peek()
1
"""

def __init__(self):

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:

"""Initializes an empty Fibonacci heap."""
self.min_node = None
self.size = 0

def is_empty(self):

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: is_empty. If the function does not return a value, please provide the type hint as: def function() -> None:

"""Return True if heap is empty"""
"""
Checks if the heap is empty.

Returns:
bool: True if heap is empty, False otherwise.
"""
return self.min_node is None

def insert(self, val):
"""Insert a new key into the heap"""
"""
Inserts a new value into the heap.

Args:
val: Value to insert.

Returns:
Node: The newly created node.
"""
node = Node(val)
if not self.min_node:
self.min_node = node
Expand All @@ -91,13 +134,26 @@
return node

def peek(self):
"""Return minimum value without removing it"""
"""
Returns the minimum value without removing it.

Returns:
The minimum value in the heap.

Raises:
IndexError: If the heap is empty.
"""
if not self.min_node:
raise IndexError("Heap is empty")
return self.min_node.val

def merge_heaps(self, other):
"""Merge another Fibonacci heap with this one"""
"""
Merges another Fibonacci heap into this one.

Args:
other: Another FibonacciHeap instance to merge with this one.
"""
if not other.min_node:
return
if not self.min_node:
Expand All @@ -115,7 +171,13 @@
self.size += other.size

def __link_trees(self, node1, node2):
"""Link two trees of same degree"""
"""
Links two trees of same degree.

Args:
node1: First tree's root node.
node2: Second tree's root node.
"""
node1.remove()
if node2.child:
node2.child.add_sibling(node1)
Expand All @@ -126,7 +188,15 @@
node1.mark = False

def delete_min(self):
"""Remove and return the minimum value"""
"""
Removes and returns the minimum value from the heap.

Returns:
The minimum value that was removed.

Raises:
IndexError: If the heap is empty.
"""
if not self.min_node:
raise IndexError("Heap is empty")

Expand Down Expand Up @@ -156,8 +226,12 @@
return min_val

def __consolidate(self):
"""Consolidate trees after delete_min"""
max_degree = int(self.size**0.5) + 1
"""
Consolidates the trees in the heap after a delete_min operation.

This is an internal method that maintains the heap's structure.
"""
max_degree = int(self.size ** 0.5) + 1
degree_table = [None] * max_degree

# Collect all roots
Expand Down Expand Up @@ -195,7 +269,16 @@
self.min_node = degree_table[degree]

def decrease_key(self, node, new_val):
"""Decrease the value of a node"""
"""
Decreases the value of a node.

Check failure on line 274 in data_structures/heap/fibonacci_heap.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W293)

data_structures/heap/fibonacci_heap.py:274:1: W293 Blank line contains whitespace
Args:
node: The node whose value should be decreased.
new_val: The new value for the node.

Check failure on line 278 in data_structures/heap/fibonacci_heap.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W293)

data_structures/heap/fibonacci_heap.py:278:1: W293 Blank line contains whitespace
Raises:
ValueError: If new value is greater than current value.
"""
if new_val > node.val:
raise ValueError("New value is greater than current value")

Expand All @@ -210,7 +293,19 @@
self.min_node = node

def __cut(self, node, parent):
"""Cut a node from its parent"""
"""
Cuts a node from its parent.

Args:
node: Node to be cut.
parent: Parent of the node to be cut.
""""""
Performs cascading cut operation.

Check failure on line 304 in data_structures/heap/fibonacci_heap.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W293)

data_structures/heap/fibonacci_heap.py:304:1: W293 Blank line contains whitespace
Args:
node: Starting node for cascading cut.
"""

Check failure on line 307 in data_structures/heap/fibonacci_heap.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (ISC001)

data_structures/heap/fibonacci_heap.py:296:9: ISC001 Implicitly concatenated string literals on one line

parent.degree -= 1
if parent.child == node:
parent.child = node.right if node.right != node else None
Expand All @@ -222,16 +317,28 @@
self.min_node.add_sibling(node)

def __cascading_cut(self, node):
"""Perform cascading cut operation"""
if parent := node.parent:
"""
Performs cascading cut operation.

Args:
node: Starting node for cascading cut.
"""

parent = node.parent
if parent:
if not node.mark:
node.mark = True
else:
self.__cut(node, parent)
self.__cascading_cut(parent)

def __str__(self):
"""String representation of the heap"""
"""
Returns a string representation of the heap.

Returns:
str: A string showing the heap structure.
"""
if not self.min_node:
return "Empty heap"

Expand All @@ -252,5 +359,4 @@

if __name__ == "__main__":
import doctest

doctest.testmod()
Loading