Skip to content

Commit 8da8f36

Browse files
authored
Added Binary Heap (#46)
1 parent 810c134 commit 8da8f36

File tree

6 files changed

+235
-1
lines changed

6 files changed

+235
-1
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Gagandeep Singh<singh.23@iitj.ac.in>
22
Kartikei Mittal<kartikeimittal@gmail.com>
3+
Umesh<23umesh.here@gmail.com>
34

pydatastructs/linear_data_structures/arrays.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ def delete(self, idx):
248248
self[idx] != None:
249249
self[idx] = None
250250
self._num -= 1
251+
if self._last_pos_filled == idx:
252+
self._last_pos_filled -= 1
251253
return self._modify()
252254

253255
@property

pydatastructs/trees/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@
1414
OneDimensionalSegmentTree
1515
)
1616
__all__.extend(space_partitioning_trees.__all__)
17+
18+
from .heaps import (
19+
BinaryHeap
20+
)
21+
__all__.extend(heaps.__all__)

pydatastructs/trees/heaps.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
from pydatastructs.utils.misc_util import _check_type, NoneType, TreeNode
2+
from pydatastructs.linear_data_structures.arrays import ArrayForTrees
3+
4+
__all__ = [
5+
'BinaryHeap'
6+
]
7+
8+
class Heap:
9+
"""
10+
Abstract class for representing heaps.
11+
"""
12+
pass
13+
14+
class BinaryHeap:
15+
"""
16+
Represents Binary Heap.
17+
18+
Parameters
19+
==========
20+
21+
elements : list, tuple
22+
Optional, by default 'None'.
23+
List/tuple of initial elements in Heap.
24+
25+
heap_property : str
26+
The property of binary heap.
27+
If the key stored in each node is
28+
either greater than or equal to
29+
the keys in the node's children
30+
then pass 'max'.
31+
If the key stored in each node is
32+
either less than or equal to
33+
the keys in the node's children
34+
then pass 'min'.
35+
By default, the heap property is
36+
set to 'min'.
37+
38+
Examples
39+
========
40+
41+
>>> from pydatastructs.trees.heaps import BinaryHeap
42+
>>> min_heap = BinaryHeap(heap_property="min")
43+
>>> min_heap.insert(1, 1)
44+
>>> min_heap.insert(5, 5)
45+
>>> min_heap.insert(7, 7)
46+
>>> min_heap.extract().key
47+
1
48+
>>> min_heap.insert(4, 4)
49+
>>> min_heap.extract().key
50+
4
51+
52+
>>> max_heap = BinaryHeap(heap_property='max')
53+
>>> max_heap.insert(1, 1)
54+
>>> max_heap.insert(5, 5)
55+
>>> max_heap.insert(7, 7)
56+
>>> max_heap.extract().key
57+
7
58+
>>> max_heap.insert(6, 6)
59+
>>> max_heap.extract().key
60+
6
61+
62+
References
63+
==========
64+
65+
.. [1] https://en.m.wikipedia.org/wiki/Binary_heap
66+
"""
67+
__slots__ = ['_comp', 'heap', 'heap_property', '_last_pos_filled']
68+
69+
def __new__(cls, elements=None, heap_property="min"):
70+
obj = object.__new__(cls)
71+
obj.heap_property = heap_property
72+
if heap_property == "min":
73+
obj._comp = lambda key_parent, key_child: key_parent <= key_child
74+
elif heap_property == "max":
75+
obj._comp = lambda key_parent, key_child: key_parent >= key_child
76+
else:
77+
raise ValueError("%s is invalid heap property"%(heap_property))
78+
if elements is None:
79+
elements = []
80+
obj.heap = elements
81+
obj._last_pos_filled = len(elements) - 1
82+
obj._build()
83+
return obj
84+
85+
def _build(self):
86+
for i in range(self._last_pos_filled + 1):
87+
self.heap[i].left, self.heap[i].right = \
88+
2*i + 1, 2*i + 2
89+
for i in range((self._last_pos_filled + 1)//2, -1, -1):
90+
self._heapify(i)
91+
92+
def _swap(self, idx1, idx2):
93+
idx1_key, idx1_data = \
94+
self.heap[idx1].key, self.heap[idx1].data
95+
self.heap[idx1].key, self.heap[idx1].data = \
96+
self.heap[idx2].key, self.heap[idx2].data
97+
self.heap[idx2].key, self.heap[idx2].data = \
98+
idx1_key, idx1_data
99+
100+
def _heapify(self, i):
101+
target = i
102+
l = 2*i + 1
103+
r = 2*i + 2
104+
105+
if l <= self._last_pos_filled:
106+
target = l if self._comp(self.heap[l].key, self.heap[target].key) \
107+
else i
108+
if r <= self._last_pos_filled:
109+
target = r if self._comp(self.heap[r].key, self.heap[target].key) \
110+
else target
111+
112+
if target != i:
113+
self._swap(target, i)
114+
i = target
115+
self._heapify(i)
116+
117+
def insert(self, key, data):
118+
"""
119+
Insert a new element to the heap according to heap property.
120+
121+
Parameters
122+
==========
123+
124+
key
125+
The key for comparison.
126+
data
127+
The data to be inserted.
128+
129+
Returns
130+
=======
131+
132+
None
133+
"""
134+
new_node = TreeNode(key, data)
135+
self.heap.append(new_node)
136+
self._last_pos_filled += 1
137+
i = self._last_pos_filled
138+
self.heap[i].left, self.heap[i].right = 2*i + 1, 2*i + 2
139+
140+
while True:
141+
parent = (i - 1)//2
142+
if i == 0 or self._comp(self.heap[parent].key, self.heap[i].key):
143+
break
144+
else:
145+
self._swap(i, parent)
146+
i = parent
147+
148+
def extract(self):
149+
"""
150+
Extract root element of the Heap.
151+
152+
Returns
153+
=======
154+
155+
root_element : TreeNode
156+
The TreeNode at the root of the heap,
157+
if the heap is not empty.
158+
None
159+
If the heap is empty.
160+
"""
161+
if self._last_pos_filled == -1:
162+
return None
163+
else:
164+
element_to_be_extracted = TreeNode(self.heap[0].key, self.heap[0].data)
165+
self._swap(0, self._last_pos_filled)
166+
self.heap[self._last_pos_filled] = TreeNode(float('inf') if self.heap_property == 'min'
167+
else float('-inf'), None)
168+
self._heapify(0)
169+
self.heap.pop()
170+
self._last_pos_filled -= 1
171+
return element_to_be_extracted
172+
173+
def __str__(self):
174+
to_be_printed = ['' for i in range(self._last_pos_filled + 1)]
175+
for i in range(self._last_pos_filled + 1):
176+
node = self.heap[i]
177+
to_be_printed[i] = (node.left if node.left <= self._last_pos_filled else None,
178+
node.key, node.data,
179+
node.right if node.right <= self._last_pos_filled else None)
180+
return str(to_be_printed)

pydatastructs/trees/tests/test_binary_trees.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_BinarySearchTree():
3333
assert b.delete(13) == None
3434
assert str(b) == \
3535
("[(1, 8, 8, 7), (3, 4, 4, 4), '', (None, 1, 1, None), "
36-
"(None, 6, 6, 6), '', (None, 7, 7, None), (None, 14, 14, None), '']")
36+
"(None, 6, 6, 6), '', (None, 7, 7, None), (None, 14, 14, None)]")
3737
b.delete(7)
3838
b.delete(6)
3939
b.delete(1)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from pydatastructs.trees.heaps import BinaryHeap
2+
from pydatastructs.utils.misc_util import TreeNode
3+
from pydatastructs.utils.raises_util import raises
4+
5+
def test_BinaryHeap():
6+
7+
max_heap = BinaryHeap(heap_property="max")
8+
9+
assert max_heap.extract() is None
10+
11+
max_heap.insert(100, 100)
12+
max_heap.insert(19, 19)
13+
max_heap.insert(36, 36)
14+
max_heap.insert(17, 17)
15+
max_heap.insert(3, 3)
16+
max_heap.insert(25, 25)
17+
max_heap.insert(1, 1)
18+
max_heap.insert(2, 2)
19+
max_heap.insert(7, 7)
20+
assert str(max_heap) == \
21+
("[(1, 100, 100, 2), (3, 19, 19, 4), "
22+
"(5, 36, 36, 6), (7, 17, 17, 8), "
23+
"(None, 3, 3, None), (None, 25, 25, None), "
24+
"(None, 1, 1, None), (None, 2, 2, None), (None, 7, 7, None)]")
25+
26+
expected_extracted_element = max_heap.heap[0].key
27+
assert max_heap.extract().key == expected_extracted_element
28+
29+
expected_sorted_elements = [36, 25, 19, 17, 7, 3, 2, 1]
30+
sorted_elements = []
31+
for _ in range(8):
32+
sorted_elements.append(max_heap.extract().key)
33+
assert expected_sorted_elements == sorted_elements
34+
35+
elements = [
36+
TreeNode(7, 7), TreeNode(25, 25), TreeNode(100, 100),
37+
TreeNode(1, 1), TreeNode(2, 2), TreeNode(3, 3),
38+
TreeNode(17, 17), TreeNode(19, 19), TreeNode(36, 36)
39+
]
40+
min_heap = BinaryHeap(elements = elements, heap_property="min")
41+
expected_extracted_element = min_heap.heap[0].key
42+
assert min_heap.extract().key == expected_extracted_element
43+
44+
expected_sorted_elements = [2, 3, 7, 17, 19, 25, 36, 100]
45+
sorted_elements = [min_heap.extract().key for _ in range(8)]
46+
assert expected_sorted_elements == sorted_elements

0 commit comments

Comments
 (0)