Skip to content

Commit 8c3b8b3

Browse files
authored
Fix TheAlgorithms#9095 : Implement Fibonacci Heap data structure
This commit introduces the Fibonacci Heap data structure along with its relevant methods.
1 parent eaa87bd commit 8c3b8b3

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed
+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Implementation of a Fibonacci Heap based on the concepts described in "Introduction to Algorithms" by Cormen, Leiserson, Rivest, and Stein.
2+
# Reference: https://en.wikipedia.org/wiki/Fibonacci_heap
3+
4+
from __future__ import annotations
5+
from collections.abc import Iterable, Iterator
6+
from typing import Any, Generic, TypeVar
7+
8+
T = TypeVar("T", bound=int)
9+
10+
11+
class FibonacciNode(Generic[T]):
12+
def __init__(self, key: T) -> None:
13+
"""
14+
Create a new FibonacciNode with the given key.
15+
16+
Args:
17+
key (T): The key value associated with the node.
18+
"""
19+
self.key: T = key
20+
self.degree: int = 0
21+
self.parent: FibonacciNode[T] | None = None
22+
self.child: FibonacciNode[T] | None = None
23+
self.is_marked: bool = False
24+
self.next: FibonacciNode[T] = self
25+
self.prev: FibonacciNode[T] = self
26+
27+
28+
class FibonacciHeap(Generic[T]):
29+
def __init__(self) -> None:
30+
"""
31+
Create a new Fibonacci Heap.
32+
33+
The Fibonacci Heap is initialized as an empty heap.
34+
"""
35+
self.min_node: FibonacciNode[T] | None = None
36+
self.num_nodes: int = 0
37+
38+
def insert(self, key: T) -> None:
39+
"""
40+
Insert a new node with the given key into the Fibonacci Heap.
41+
42+
Args:
43+
key (T): The key value to insert.
44+
"""
45+
new_node = FibonacciNode(key)
46+
if self.min_node is None:
47+
self.min_node = new_node
48+
else:
49+
self._link_nodes(self.min_node, new_node)
50+
if key < self.min_node.key:
51+
self.min_node = new_node
52+
self.num_nodes += 1
53+
54+
def _link_nodes(self, min_node: FibonacciNode[T], new_node: FibonacciNode[T]) -> None:
55+
"""
56+
Link two nodes together in the Fibonacci Heap.
57+
58+
Args:
59+
min_node (FibonacciNode): The minimum node.
60+
new_node (FibonacciNode): The new node to be linked.
61+
"""
62+
new_node.next = min_node.next
63+
min_node.next = new_node
64+
new_node.prev = min_node
65+
new_node.next.prev = new_node
66+
67+
def _consolidate(self) -> None:
68+
"""
69+
Consolidate the heap by combining trees with the same degree.
70+
71+
This is an internal method used to maintain the Fibonacci Heap's properties.
72+
"""
73+
max_degree = int(self.num_nodes ** 0.5) + 1
74+
degree_buckets: list[FibonacciNode[T] | None] = [None] * max_degree
75+
76+
current_node = self.min_node
77+
nodes_to_visit = [current_node]
78+
while True:
79+
current_node = current_node.next
80+
if current_node == self.min_node:
81+
break
82+
nodes_to_visit.append(current_node)
83+
84+
for node in nodes_to_visit:
85+
degree = node.degree
86+
while degree_buckets[degree]:
87+
other = degree_buckets[degree]
88+
if node.key > other.key:
89+
node, other = other, node
90+
self._link_nodes(node, other)
91+
degree_buckets[degree] = None
92+
degree += 1
93+
degree_buckets[degree] = node
94+
95+
self.min_node = None
96+
for node in degree_buckets:
97+
if node:
98+
if self.min_node is None or node.key < self.min_node.key:
99+
self.min_node = node
100+
101+
def extract_min(self) -> T | None:
102+
"""
103+
Extract the minimum element from the Fibonacci Heap.
104+
105+
Returns:
106+
T | None: The minimum element, or None if the heap is empty.
107+
"""
108+
min_node = self.min_node
109+
if min_node:
110+
if min_node.child:
111+
child = min_node.child
112+
while True:
113+
next_child = child.next
114+
child.prev = min_node.prev
115+
child.next = min_node.next
116+
min_node.prev.next = child
117+
min_node.next.prev = child
118+
min_node.child = None
119+
if next_child == min_node.child:
120+
break
121+
child = next_child
122+
self._remove_node(min_node)
123+
if min_node == min_node.next:
124+
self.min_node = None
125+
else:
126+
self.min_node = min_node.next
127+
self._consolidate()
128+
self.num_nodes -= 1
129+
return min_node.key if min_node else None
130+
131+
def _remove_node(self, node: FibonacciNode[T]) -> None:
132+
"""
133+
Remove a node from the doubly linked list of nodes.
134+
135+
Args:
136+
node (FibonacciNode): The node to remove.
137+
"""
138+
node.prev.next = node.next
139+
node.next.prev = node.prev
140+
141+
if __name__ == "__main__":
142+
import doctest
143+
doctest.testmod()
144+

0 commit comments

Comments
 (0)