Skip to content

Commit

Permalink
Added tests and docstrings to fibonacci_heap.py
Browse files Browse the repository at this point in the history
  • Loading branch information
mcawezome committed Nov 18, 2024
1 parent ea5a187 commit a92936b
Showing 1 changed file with 135 additions and 29 deletions.
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 @@ def __init__(self, val):
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):
"""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 @@ def add_child(self, node):
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):
"""Initializes an empty Fibonacci heap."""
self.min_node = None
self.size = 0

def is_empty(self):
"""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 @@ def insert(self, val):
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 @@ def merge_heaps(self, other):
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 @@ def __link_trees(self, node1, node2):
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 @@ def delete_min(self):
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 @@ def __consolidate(self):
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 @@ def decrease_key(self, node, new_val):
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 @@ def __cut(self, node, parent):
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 @@ def print_tree(node, level=0):

if __name__ == "__main__":
import doctest

doctest.testmod()

0 comments on commit a92936b

Please sign in to comment.