forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfibonacci_heap.py
More file actions
167 lines (138 loc) · 5.24 KB
/
fibonacci_heap.py
File metadata and controls
167 lines (138 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"""Fibonacci Heap implementation - An advanced priority queue data structure.
A Fibonacci heap is a heap data structure consisting of a collection of heap-ordered
trees. It has a better amortized running time than other heap types, particularly for
the decrease-key operation which runs in amortized O(1) time.
This makes Fibonacci heaps ideal for algorithms like Dijkstra's shortest path and
Prim's minimum spanning tree algorithm.
For more information, see: https://en.wikipedia.org/wiki/Fibonacci_heap
Time Complexity (amortized):
- Insert: O(1)
- Find minimum: O(1)
- Delete minimum: O(log n)
- Decrease key: O(1)
- Merge: O(1)
Space Complexity: O(n)
"""
from __future__ import annotations
from typing import Any
class FibonacciNode:
"""A node in the Fibonacci heap."""
def __init__(self, key: Any, value: Any = None) -> None:
self.key = key # Priority key
self.value = value # Associated data
self.parent: FibonacciNode | None = None
self.child: FibonacciNode | None = None
self.left: FibonacciNode | None = None # Left sibling
self.right: FibonacciNode | None = None # Right sibling
self.degree = 0 # Number of children
self.marked = False # Whether node has lost a child since becoming a child
class FibonacciHeap:
"""
Fibonacci Heap implementation - Advanced priority queue.
This implementation provides amortized O(1) decrease-key operations,
making it suitable for algorithms requiring frequent priority updates.
Example:
>>> heap = FibonacciHeap()
>>> heap.insert(10, "ten")
>>> heap.insert(5, "five")
>>> heap.insert(15, "fifteen")
>>> heap.find_min()
(5, 'five')
>>> heap.extract_min()
(5, 'five')
>>> heap.find_min()
(10, 'ten')
"""
def __init__(self) -> None:
"""Initialize an empty Fibonacci heap."""
self.min_node: FibonacciNode | None = None
self.total_nodes = 0
def __bool__(self) -> bool:
"""Return True if the heap is not empty."""
return self.min_node is not None
def __len__(self) -> int:
"""Return the number of nodes in the heap."""
return self.total_nodes
def is_empty(self) -> bool:
"""Check if the heap is empty."""
return self.min_node is None
def insert(self, key: Any, value: Any = None) -> None:
"""Insert a new key-value pair into the heap."""
node = FibonacciNode(key, value)
if not self.min_node:
self.min_node = node
node.left = node
node.right = node
else:
# Insert into root list
assert self.min_node.right is not None
assert self.min_node.left is not None
node.left = self.min_node
node.right = self.min_node.right
self.min_node.right.left = node
self.min_node.right = node
if key < self.min_node.key:
self.min_node = node
self.total_nodes += 1
def find_min(self):
"""Find the minimum key-value pair without removing it."""
if not self.min_node:
return None
return (self.min_node.key, self.min_node.value)
def extract_min(self):
"""Extract and return the minimum key-value pair."""
if not self.min_node:
return None
min_node = self.min_node
result = (min_node.key, min_node.value)
# Handle children
if min_node.child:
child = min_node.child
while True:
next_child = child.right
# Add child to root list
child.left = min_node.left
child.right = min_node.right
min_node.left.right = child
min_node.right.left = child
child.parent = None
child = next_child
if child == min_node.child:
break
# Remove min_node from root list
if min_node.left == min_node:
self.min_node = None
else:
min_node.left.right = min_node.right
min_node.right.left = min_node.left
self.min_node = min_node.right
# Find new minimum
current = self.min_node
min_key = current.key
start = current
current = current.right
while current != start:
if current.key < min_key:
min_key = current.key
self.min_node = current
current = current.right
self.total_nodes -= 1
return result
def merge(self, other):
"""Merge this heap with another Fibonacci heap."""
if not other.min_node:
return self
if not self.min_node:
self.min_node = other.min_node
self.total_nodes = other.total_nodes
return self
# Merge root lists
self.min_node.left.right = other.min_node.right
other.min_node.right.left = self.min_node.left
self.min_node.left = other.min_node.left
other.min_node.left.right = self.min_node
# Update minimum
if other.min_node.key < self.min_node.key:
self.min_node = other.min_node
self.total_nodes += other.total_nodes
return self