Skip to content

Commit 6ac7b13

Browse files
Raj1998cclauss
authored andcommitted
Min head with decrease key functionality (#1202)
* Min head with decrease key functionality * doctest added * __str__ changed as per Python convention * edits in doctest * get_value by key added * __getitem__ added
1 parent e40d4a2 commit 6ac7b13

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

Diff for: data_structures/heap/min_heap.py

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Min head data structure
2+
# with decrease key functionality - in O(log(n)) time
3+
4+
5+
class Node:
6+
def __init__(self, name, val):
7+
self.name = name
8+
self.val = val
9+
10+
def __str__(self):
11+
return f"{self.__class__.__name__}({self.name}, {self.val})"
12+
13+
def __lt__(self, other):
14+
return self.val < other.val
15+
16+
17+
class MinHeap:
18+
"""
19+
>>> r = Node("R", -1)
20+
>>> b = Node("B", 6)
21+
>>> a = Node("A", 3)
22+
>>> x = Node("X", 1)
23+
>>> e = Node("E", 4)
24+
>>> print(b)
25+
Node(B, 6)
26+
>>> myMinHeap = MinHeap([r, b, a, x, e])
27+
>>> myMinHeap.decrease_key(b, -17)
28+
>>> print(b)
29+
Node(B, -17)
30+
>>> print(myMinHeap["B"])
31+
-17
32+
"""
33+
34+
def __init__(self, array):
35+
self.idx_of_element = {}
36+
self.heap_dict = {}
37+
self.heap = self.build_heap(array)
38+
39+
def __getitem__(self, key):
40+
return self.get_value(key)
41+
42+
def get_parent_idx(self, idx):
43+
return (idx - 1) // 2
44+
45+
def get_left_child_idx(self, idx):
46+
return idx * 2 + 1
47+
48+
def get_right_child_idx(self, idx):
49+
return idx * 2 + 2
50+
51+
def get_value(self, key):
52+
return self.heap_dict[key]
53+
54+
def build_heap(self, array):
55+
lastIdx = len(array) - 1
56+
startFrom = self.get_parent_idx(lastIdx)
57+
58+
for idx, i in enumerate(array):
59+
self.idx_of_element[i] = idx
60+
self.heap_dict[i.name] = i.val
61+
62+
for i in range(startFrom, -1, -1):
63+
self.sift_down(i, array)
64+
return array
65+
66+
# this is min-heapify method
67+
def sift_down(self, idx, array):
68+
while True:
69+
l = self.get_left_child_idx(idx)
70+
r = self.get_right_child_idx(idx)
71+
72+
smallest = idx
73+
if l < len(array) and array[l] < array[idx]:
74+
smallest = l
75+
if r < len(array) and array[r] < array[smallest]:
76+
smallest = r
77+
78+
if smallest != idx:
79+
array[idx], array[smallest] = array[smallest], array[idx]
80+
self.idx_of_element[array[idx]], self.idx_of_element[
81+
array[smallest]
82+
] = (
83+
self.idx_of_element[array[smallest]],
84+
self.idx_of_element[array[idx]],
85+
)
86+
idx = smallest
87+
else:
88+
break
89+
90+
def sift_up(self, idx):
91+
p = self.get_parent_idx(idx)
92+
while p >= 0 and self.heap[p] > self.heap[idx]:
93+
self.heap[p], self.heap[idx] = self.heap[idx], self.heap[p]
94+
self.idx_of_element[self.heap[p]], self.idx_of_element[self.heap[idx]] = (
95+
self.idx_of_element[self.heap[idx]],
96+
self.idx_of_element[self.heap[p]],
97+
)
98+
idx = p
99+
p = self.get_parent_idx(idx)
100+
101+
def peek(self):
102+
return self.heap[0]
103+
104+
def remove(self):
105+
self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0]
106+
self.idx_of_element[self.heap[0]], self.idx_of_element[self.heap[-1]] = (
107+
self.idx_of_element[self.heap[-1]],
108+
self.idx_of_element[self.heap[0]],
109+
)
110+
111+
x = self.heap.pop()
112+
del self.idx_of_element[x]
113+
self.sift_down(0, self.heap)
114+
return x
115+
116+
def insert(self, node):
117+
self.heap.append(node)
118+
self.idx_of_element[node] = len(self.heap) - 1
119+
self.heap_dict[node.name] = node.val
120+
self.sift_up(len(self.heap) - 1)
121+
122+
def is_empty(self):
123+
return True if len(self.heap) == 0 else False
124+
125+
def decrease_key(self, node, newValue):
126+
assert (
127+
self.heap[self.idx_of_element[node]].val > newValue
128+
), "newValue must be less that current value"
129+
node.val = newValue
130+
self.heap_dict[node.name] = newValue
131+
self.sift_up(self.idx_of_element[node])
132+
133+
134+
## USAGE
135+
136+
r = Node("R", -1)
137+
b = Node("B", 6)
138+
a = Node("A", 3)
139+
x = Node("X", 1)
140+
e = Node("E", 4)
141+
142+
# Use one of these two ways to generate Min-Heap
143+
144+
# Generating Min-Heap from array
145+
myMinHeap = MinHeap([r, b, a, x, e])
146+
147+
# Generating Min-Heap by Insert method
148+
# myMinHeap.insert(a)
149+
# myMinHeap.insert(b)
150+
# myMinHeap.insert(x)
151+
# myMinHeap.insert(r)
152+
# myMinHeap.insert(e)
153+
154+
# Before
155+
print("Min Heap - before decrease key")
156+
for i in myMinHeap.heap:
157+
print(i)
158+
159+
print("Min Heap - After decrease key of node [B -> -17]")
160+
myMinHeap.decrease_key(b, -17)
161+
162+
# After
163+
for i in myMinHeap.heap:
164+
print(i)
165+
166+
if __name__ == "__main__":
167+
import doctest
168+
169+
doctest.testmod()

0 commit comments

Comments
 (0)