Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a92936b

Browse files
committedNov 18, 2024·
Added tests and docstrings to fibonacci_heap.py
1 parent ea5a187 commit a92936b

File tree

1 file changed

+135
-29
lines changed

1 file changed

+135
-29
lines changed
 

‎data_structures/heap/fibonacci_heap.py

Lines changed: 135 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Fibonacci Heap
33
A more efficient priority queue implementation that provides amortized time bounds
44
that are better than those of the binary and binomial heaps.
5+
reference: https://en.wikipedia.org/wiki/Fibonacci_heap
56
67
Operations supported:
78
- Insert: O(1) amortized
@@ -11,17 +12,22 @@
1112
- Merge: O(1)
1213
"""
1314

14-
1515
class Node:
1616
"""
17-
Node in a Fibonacci heap containing:
18-
- value
19-
- parent, child, and sibling links
20-
- degree (number of children)
21-
- mark (whether the node has lost a child since
22-
becoming a child of its current parent)
17+
A node in a Fibonacci heap.
18+
19+
Args:
20+
val: The value stored in the node.
21+
22+
Attributes:
23+
val: The value stored in the node.
24+
parent: Reference to parent node.
25+
child: Reference to one child node.
26+
left: Reference to left sibling.
27+
right: Reference to right sibling.
28+
degree: Number of children.
29+
mark: Boolean indicating if node has lost a child.
2330
"""
24-
2531
def __init__(self, val):
2632
self.val = val
2733
self.parent = None
@@ -32,14 +38,24 @@ def __init__(self, val):
3238
self.mark = False
3339

3440
def add_sibling(self, node):
35-
"""Add node as a sibling"""
41+
"""
42+
Adds a node as a sibling to the current node.
43+
44+
Args:
45+
node: The node to add as a sibling.
46+
"""
3647
node.left = self
3748
node.right = self.right
3849
self.right.left = node
3950
self.right = node
4051

4152
def add_child(self, node):
42-
"""Add node as a child"""
53+
"""
54+
Adds a node as a child of the current node.
55+
56+
Args:
57+
node: The node to add as a child.
58+
"""
4359
node.parent = self
4460
if not self.child:
4561
self.child = node
@@ -48,38 +64,65 @@ def add_child(self, node):
4864
self.degree += 1
4965

5066
def remove(self):
51-
"""Remove this node from its sibling list"""
67+
"""Removes this node from its sibling list."""
5268
self.left.right = self.right
5369
self.right.left = self.left
5470

5571

5672
class FibonacciHeap:
5773
"""
58-
Min-oriented Fibonacci heap implementation.
74+
A Fibonacci heap implementation providing
75+
amortized efficient priority queue operations.
76+
77+
This implementation provides the following time complexities:
78+
- Insert: O(1) amortized
79+
- Find minimum: O(1)
80+
- Delete minimum: O(log n) amortized
81+
- Decrease key: O(1) amortized
82+
- Merge: O(1)
5983
6084
Example:
6185
>>> heap = FibonacciHeap()
62-
>>> heap.insert(3)
63-
>>> heap.insert(2)
64-
>>> heap.insert(15)
86+
>>> node1 = heap.insert(3)
87+
>>> node2 = heap.insert(2)
88+
>>> node3 = heap.insert(15)
6589
>>> heap.peek()
6690
2
6791
>>> heap.delete_min()
6892
2
6993
>>> heap.peek()
7094
3
95+
>>> other_heap = FibonacciHeap()
96+
>>> node4 = other_heap.insert(1)
97+
>>> heap.merge_heaps(other_heap)
98+
>>> heap.peek()
99+
1
71100
"""
72101

73102
def __init__(self):
103+
"""Initializes an empty Fibonacci heap."""
74104
self.min_node = None
75105
self.size = 0
76106

77107
def is_empty(self):
78-
"""Return True if heap is empty"""
108+
"""
109+
Checks if the heap is empty.
110+
111+
Returns:
112+
bool: True if heap is empty, False otherwise.
113+
"""
79114
return self.min_node is None
80115

81116
def insert(self, val):
82-
"""Insert a new key into the heap"""
117+
"""
118+
Inserts a new value into the heap.
119+
120+
Args:
121+
val: Value to insert.
122+
123+
Returns:
124+
Node: The newly created node.
125+
"""
83126
node = Node(val)
84127
if not self.min_node:
85128
self.min_node = node
@@ -91,13 +134,26 @@ def insert(self, val):
91134
return node
92135

93136
def peek(self):
94-
"""Return minimum value without removing it"""
137+
"""
138+
Returns the minimum value without removing it.
139+
140+
Returns:
141+
The minimum value in the heap.
142+
143+
Raises:
144+
IndexError: If the heap is empty.
145+
"""
95146
if not self.min_node:
96147
raise IndexError("Heap is empty")
97148
return self.min_node.val
98149

99150
def merge_heaps(self, other):
100-
"""Merge another Fibonacci heap with this one"""
151+
"""
152+
Merges another Fibonacci heap into this one.
153+
154+
Args:
155+
other: Another FibonacciHeap instance to merge with this one.
156+
"""
101157
if not other.min_node:
102158
return
103159
if not self.min_node:
@@ -115,7 +171,13 @@ def merge_heaps(self, other):
115171
self.size += other.size
116172

117173
def __link_trees(self, node1, node2):
118-
"""Link two trees of same degree"""
174+
"""
175+
Links two trees of same degree.
176+
177+
Args:
178+
node1: First tree's root node.
179+
node2: Second tree's root node.
180+
"""
119181
node1.remove()
120182
if node2.child:
121183
node2.child.add_sibling(node1)
@@ -126,7 +188,15 @@ def __link_trees(self, node1, node2):
126188
node1.mark = False
127189

128190
def delete_min(self):
129-
"""Remove and return the minimum value"""
191+
"""
192+
Removes and returns the minimum value from the heap.
193+
194+
Returns:
195+
The minimum value that was removed.
196+
197+
Raises:
198+
IndexError: If the heap is empty.
199+
"""
130200
if not self.min_node:
131201
raise IndexError("Heap is empty")
132202

@@ -156,8 +226,12 @@ def delete_min(self):
156226
return min_val
157227

158228
def __consolidate(self):
159-
"""Consolidate trees after delete_min"""
160-
max_degree = int(self.size**0.5) + 1
229+
"""
230+
Consolidates the trees in the heap after a delete_min operation.
231+
232+
This is an internal method that maintains the heap's structure.
233+
"""
234+
max_degree = int(self.size ** 0.5) + 1
161235
degree_table = [None] * max_degree
162236

163237
# Collect all roots
@@ -195,7 +269,16 @@ def __consolidate(self):
195269
self.min_node = degree_table[degree]
196270

197271
def decrease_key(self, node, new_val):
198-
"""Decrease the value of a node"""
272+
"""
273+
Decreases the value of a node.
274+
275+
Args:
276+
node: The node whose value should be decreased.
277+
new_val: The new value for the node.
278+
279+
Raises:
280+
ValueError: If new value is greater than current value.
281+
"""
199282
if new_val > node.val:
200283
raise ValueError("New value is greater than current value")
201284

@@ -210,7 +293,19 @@ def decrease_key(self, node, new_val):
210293
self.min_node = node
211294

212295
def __cut(self, node, parent):
213-
"""Cut a node from its parent"""
296+
"""
297+
Cuts a node from its parent.
298+
299+
Args:
300+
node: Node to be cut.
301+
parent: Parent of the node to be cut.
302+
""""""
303+
Performs cascading cut operation.
304+
305+
Args:
306+
node: Starting node for cascading cut.
307+
"""
308+
214309
parent.degree -= 1
215310
if parent.child == node:
216311
parent.child = node.right if node.right != node else None
@@ -222,16 +317,28 @@ def __cut(self, node, parent):
222317
self.min_node.add_sibling(node)
223318

224319
def __cascading_cut(self, node):
225-
"""Perform cascading cut operation"""
226-
if parent := node.parent:
320+
"""
321+
Performs cascading cut operation.
322+
323+
Args:
324+
node: Starting node for cascading cut.
325+
"""
326+
327+
parent = node.parent
328+
if parent:
227329
if not node.mark:
228330
node.mark = True
229331
else:
230332
self.__cut(node, parent)
231333
self.__cascading_cut(parent)
232334

233335
def __str__(self):
234-
"""String representation of the heap"""
336+
"""
337+
Returns a string representation of the heap.
338+
339+
Returns:
340+
str: A string showing the heap structure.
341+
"""
235342
if not self.min_node:
236343
return "Empty heap"
237344

@@ -252,5 +359,4 @@ def print_tree(node, level=0):
252359

253360
if __name__ == "__main__":
254361
import doctest
255-
256362
doctest.testmod()

0 commit comments

Comments
 (0)
Please sign in to comment.