-
Notifications
You must be signed in to change notification settings - Fork 269
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
235 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
Gagandeep Singh<[email protected]> | ||
Kartikei Mittal<[email protected]> | ||
Umesh<[email protected]> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
from pydatastructs.utils.misc_util import _check_type, NoneType, TreeNode | ||
from pydatastructs.linear_data_structures.arrays import ArrayForTrees | ||
|
||
__all__ = [ | ||
'BinaryHeap' | ||
] | ||
|
||
class Heap: | ||
""" | ||
Abstract class for representing heaps. | ||
""" | ||
pass | ||
|
||
class BinaryHeap: | ||
""" | ||
Represents Binary Heap. | ||
Parameters | ||
========== | ||
elements : list, tuple | ||
Optional, by default 'None'. | ||
List/tuple of initial elements in Heap. | ||
heap_property : str | ||
The property of binary heap. | ||
If the key stored in each node is | ||
either greater than or equal to | ||
the keys in the node's children | ||
then pass 'max'. | ||
If the key stored in each node is | ||
either less than or equal to | ||
the keys in the node's children | ||
then pass 'min'. | ||
By default, the heap property is | ||
set to 'min'. | ||
Examples | ||
======== | ||
>>> from pydatastructs.trees.heaps import BinaryHeap | ||
>>> min_heap = BinaryHeap(heap_property="min") | ||
>>> min_heap.insert(1, 1) | ||
>>> min_heap.insert(5, 5) | ||
>>> min_heap.insert(7, 7) | ||
>>> min_heap.extract().key | ||
1 | ||
>>> min_heap.insert(4, 4) | ||
>>> min_heap.extract().key | ||
4 | ||
>>> max_heap = BinaryHeap(heap_property='max') | ||
>>> max_heap.insert(1, 1) | ||
>>> max_heap.insert(5, 5) | ||
>>> max_heap.insert(7, 7) | ||
>>> max_heap.extract().key | ||
7 | ||
>>> max_heap.insert(6, 6) | ||
>>> max_heap.extract().key | ||
6 | ||
References | ||
========== | ||
.. [1] https://en.m.wikipedia.org/wiki/Binary_heap | ||
""" | ||
__slots__ = ['_comp', 'heap', 'heap_property', '_last_pos_filled'] | ||
|
||
def __new__(cls, elements=None, heap_property="min"): | ||
obj = object.__new__(cls) | ||
obj.heap_property = heap_property | ||
if heap_property == "min": | ||
obj._comp = lambda key_parent, key_child: key_parent <= key_child | ||
elif heap_property == "max": | ||
obj._comp = lambda key_parent, key_child: key_parent >= key_child | ||
else: | ||
raise ValueError("%s is invalid heap property"%(heap_property)) | ||
if elements is None: | ||
elements = [] | ||
obj.heap = elements | ||
obj._last_pos_filled = len(elements) - 1 | ||
obj._build() | ||
return obj | ||
|
||
def _build(self): | ||
for i in range(self._last_pos_filled + 1): | ||
self.heap[i].left, self.heap[i].right = \ | ||
2*i + 1, 2*i + 2 | ||
for i in range((self._last_pos_filled + 1)//2, -1, -1): | ||
self._heapify(i) | ||
|
||
def _swap(self, idx1, idx2): | ||
idx1_key, idx1_data = \ | ||
self.heap[idx1].key, self.heap[idx1].data | ||
self.heap[idx1].key, self.heap[idx1].data = \ | ||
self.heap[idx2].key, self.heap[idx2].data | ||
self.heap[idx2].key, self.heap[idx2].data = \ | ||
idx1_key, idx1_data | ||
|
||
def _heapify(self, i): | ||
target = i | ||
l = 2*i + 1 | ||
r = 2*i + 2 | ||
|
||
if l <= self._last_pos_filled: | ||
target = l if self._comp(self.heap[l].key, self.heap[target].key) \ | ||
else i | ||
if r <= self._last_pos_filled: | ||
target = r if self._comp(self.heap[r].key, self.heap[target].key) \ | ||
else target | ||
|
||
if target != i: | ||
self._swap(target, i) | ||
i = target | ||
self._heapify(i) | ||
|
||
def insert(self, key, data): | ||
""" | ||
Insert a new element to the heap according to heap property. | ||
Parameters | ||
========== | ||
key | ||
The key for comparison. | ||
data | ||
The data to be inserted. | ||
Returns | ||
======= | ||
None | ||
""" | ||
new_node = TreeNode(key, data) | ||
self.heap.append(new_node) | ||
self._last_pos_filled += 1 | ||
i = self._last_pos_filled | ||
self.heap[i].left, self.heap[i].right = 2*i + 1, 2*i + 2 | ||
|
||
while True: | ||
parent = (i - 1)//2 | ||
if i == 0 or self._comp(self.heap[parent].key, self.heap[i].key): | ||
break | ||
else: | ||
self._swap(i, parent) | ||
i = parent | ||
|
||
def extract(self): | ||
""" | ||
Extract root element of the Heap. | ||
Returns | ||
======= | ||
root_element : TreeNode | ||
The TreeNode at the root of the heap, | ||
if the heap is not empty. | ||
None | ||
If the heap is empty. | ||
""" | ||
if self._last_pos_filled == -1: | ||
return None | ||
else: | ||
element_to_be_extracted = TreeNode(self.heap[0].key, self.heap[0].data) | ||
self._swap(0, self._last_pos_filled) | ||
self.heap[self._last_pos_filled] = TreeNode(float('inf') if self.heap_property == 'min' | ||
else float('-inf'), None) | ||
self._heapify(0) | ||
self.heap.pop() | ||
self._last_pos_filled -= 1 | ||
return element_to_be_extracted | ||
|
||
def __str__(self): | ||
to_be_printed = ['' for i in range(self._last_pos_filled + 1)] | ||
for i in range(self._last_pos_filled + 1): | ||
node = self.heap[i] | ||
to_be_printed[i] = (node.left if node.left <= self._last_pos_filled else None, | ||
node.key, node.data, | ||
node.right if node.right <= self._last_pos_filled else None) | ||
return str(to_be_printed) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from pydatastructs.trees.heaps import BinaryHeap | ||
from pydatastructs.utils.misc_util import TreeNode | ||
from pydatastructs.utils.raises_util import raises | ||
|
||
def test_BinaryHeap(): | ||
|
||
max_heap = BinaryHeap(heap_property="max") | ||
|
||
assert max_heap.extract() is None | ||
|
||
max_heap.insert(100, 100) | ||
max_heap.insert(19, 19) | ||
max_heap.insert(36, 36) | ||
max_heap.insert(17, 17) | ||
max_heap.insert(3, 3) | ||
max_heap.insert(25, 25) | ||
max_heap.insert(1, 1) | ||
max_heap.insert(2, 2) | ||
max_heap.insert(7, 7) | ||
assert str(max_heap) == \ | ||
("[(1, 100, 100, 2), (3, 19, 19, 4), " | ||
"(5, 36, 36, 6), (7, 17, 17, 8), " | ||
"(None, 3, 3, None), (None, 25, 25, None), " | ||
"(None, 1, 1, None), (None, 2, 2, None), (None, 7, 7, None)]") | ||
|
||
expected_extracted_element = max_heap.heap[0].key | ||
assert max_heap.extract().key == expected_extracted_element | ||
|
||
expected_sorted_elements = [36, 25, 19, 17, 7, 3, 2, 1] | ||
sorted_elements = [] | ||
for _ in range(8): | ||
sorted_elements.append(max_heap.extract().key) | ||
assert expected_sorted_elements == sorted_elements | ||
|
||
elements = [ | ||
TreeNode(7, 7), TreeNode(25, 25), TreeNode(100, 100), | ||
TreeNode(1, 1), TreeNode(2, 2), TreeNode(3, 3), | ||
TreeNode(17, 17), TreeNode(19, 19), TreeNode(36, 36) | ||
] | ||
min_heap = BinaryHeap(elements = elements, heap_property="min") | ||
expected_extracted_element = min_heap.heap[0].key | ||
assert min_heap.extract().key == expected_extracted_element | ||
|
||
expected_sorted_elements = [2, 3, 7, 17, 19, 25, 36, 100] | ||
sorted_elements = [min_heap.extract().key for _ in range(8)] | ||
assert expected_sorted_elements == sorted_elements |