Skip to content

Commit ed237f2

Browse files
Merge pull request #169 from jerryderry/heap-python
max-heap in python
2 parents c06516d + ce8b8e3 commit ed237f2

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

python/28_heap/heap.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"""
2+
Max-heap
3+
4+
Author: Wenru Dong
5+
"""
6+
7+
from typing import Optional, List
8+
9+
class Heap:
10+
def __init__(self, capacity: int):
11+
self._data = [0] * (capacity + 1)
12+
self._capacity = capacity
13+
self._count = 0
14+
15+
@classmethod
16+
def _parent(cls, child_index: int) -> int:
17+
"""The parent index."""
18+
return child_index // 2
19+
20+
@classmethod
21+
def _left(cls, parent_index: int) -> int:
22+
"""The left child index."""
23+
return 2 * parent_index
24+
25+
@classmethod
26+
def _right(cls, parent_index: int) -> int:
27+
"""The right child index."""
28+
return 2 * parent_index + 1
29+
30+
def _siftup(self) -> None:
31+
i, parent = self._count, Heap._parent(self._count)
32+
while parent and self._data[i] > self._data[parent]:
33+
self._data[i], self._data[parent] = self._data[parent], self._data[i]
34+
i, parent = parent, Heap._parent(parent)
35+
36+
@classmethod
37+
def _siftdown(cls, a: List[int], count: int, root_index: int = 1) -> None:
38+
i = larger_child_index = root_index
39+
while True:
40+
left, right = cls._left(i), cls._right(i)
41+
if left <= count and a[i] < a[left]:
42+
larger_child_index = left
43+
if right <= count and a[larger_child_index] < a[right]:
44+
larger_child_index = right
45+
if larger_child_index == i: break
46+
a[i], a[larger_child_index] = a[larger_child_index], a[i]
47+
i = larger_child_index
48+
49+
def insert(self, value: int) -> None:
50+
if self._count >= self._capacity: return
51+
self._count += 1
52+
self._data[self._count] = value
53+
self._siftup()
54+
55+
def remove_max(self) -> Optional[int]:
56+
if self._count:
57+
result = self._data[1]
58+
self._data[1] = self._data[self._count]
59+
self._count -= 1
60+
Heap._siftdown(self._data, self._count)
61+
return result
62+
63+
@classmethod
64+
def build_heap(cls, a: List[int]) -> None:
65+
"""Data in a needs to start from index 1."""
66+
for i in range((len(a) - 1)//2, 0, -1):
67+
cls._siftdown(a, len(a) - 1, i)
68+
69+
@classmethod
70+
def sort(cls, a: List[int]) -> None:
71+
"""Data in a needs to start from index 1."""
72+
cls.build_heap(a)
73+
k = len(a) - 1
74+
while k > 1:
75+
a[1], a[k] = a[k], a[1]
76+
k -= 1
77+
cls._siftdown(a, k)
78+
79+
def __repr__(self):
80+
return self._data[1 : self._count + 1].__repr__()
81+
82+
83+
if __name__ == "__main__":
84+
hp = Heap(10)
85+
hp.insert(3)
86+
hp.insert(9)
87+
hp.insert(1)
88+
hp.insert(8)
89+
hp.insert(7)
90+
hp.insert(3)
91+
print(hp)
92+
for _ in range(6):
93+
print(hp.remove_max())
94+
a = [0, 6, 3, 4, 0, 9, 2, 7, 5, -2, 8, 1, 6, 10]
95+
Heap.sort(a)
96+
print(a[1:])

0 commit comments

Comments
 (0)