Skip to content

Commit f194502

Browse files
authored
min heap
min heap with index from 0
1 parent 5187058 commit f194502

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

python/28_heap/min_heap.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
class Heap(object):
2+
'''
3+
索引从0开始的小顶堆
4+
参考: https://github.com/python/cpython/blob/master/Lib/heapq.py
5+
6+
author: Ben
7+
'''
8+
9+
def __init__(self, nums):
10+
self._heap = nums
11+
12+
def _siftup(self, pos):
13+
'''
14+
从上向下的堆化
15+
将pos节点的子节点中的最值提升到pos位置
16+
'''
17+
start = pos
18+
startval = self._heap[pos]
19+
n = len(self._heap)
20+
# 完全二叉树特性
21+
child = pos * 2 + 1
22+
# 比较叶子节点
23+
while child < n:
24+
right = child + 1
25+
# 平衡二叉树的特性, 大的都在右边
26+
if right < n and not self._heap[right] > self._heap[child]:
27+
child = right
28+
self._heap[pos] = self._heap[child]
29+
pos = child
30+
child = pos * 2 + 1
31+
self._heap[pos] = startval
32+
33+
# 此时只有pos是不确定的
34+
self._siftdown(start, pos)
35+
36+
def _siftdown(self, start, pos):
37+
'''
38+
最小堆: 大于start的节点, 除pos外已经是最小堆
39+
以pos为叶子节点, start为根节点之间的元素进行排序. 将pos叶子节点交换到正确的排序位置
40+
操作: 从叶子节点开始, 当父节点的值大于子节点时, 父节点的值降低到子节点
41+
'''
42+
startval = self._heap[pos]
43+
while pos > start:
44+
parent = (pos - 1) >> 1
45+
parentval = self._heap[parent]
46+
if parentval > startval:
47+
self._heap[pos] = parentval
48+
pos = parent
49+
continue
50+
break
51+
self._heap[pos] = startval
52+
53+
def heapify(self):
54+
'''
55+
堆化: 从后向前(从下向上)的方式堆化, _siftup中pos节点的子树已经是有序的,
56+
这样要排序的节点在慢慢减少
57+
1. 因为n/2+1到n的节点是叶子节点(完全二叉树的特性), 它们没有子节点,
58+
所以, 只需要堆化n/2到0的节点, 以对应的父节点为根节点, 将最值向上筛选,
59+
然后交换对应的根节点和查找到的最值
60+
2. 因为开始时待排序树的根节点还没有排序, 为了保证根节点的有序,
61+
需要将子树中根节点交换到正确顺序
62+
'''
63+
n = len(self._heap)
64+
for i in reversed(range(n // 2)):
65+
self._siftup(i)
66+
67+
def heappop(self):
68+
'''
69+
弹出堆首的最值 O(logn)
70+
'''
71+
tail = self._heap.pop()
72+
# 为避免破环完全二叉树特性, 将堆尾元素填充到堆首
73+
# 此时, 只有堆首是未排序的, 只需要一次从上向下的堆化
74+
if self._heap:
75+
peak = self._heap[0]
76+
self._heap[0] = tail
77+
self._siftup(0)
78+
return peak
79+
return tail
80+
81+
def heappush(self, val):
82+
'''
83+
添加元素到堆尾 O(logn)
84+
'''
85+
n = len(self._heap)
86+
self._heap.append(val)
87+
# 此时只有堆尾的节点是未排序的, 将添加的节点迭代到正确的位置
88+
self._siftdown(0, n)
89+
90+
def __repr__(self):
91+
vals = [str(i) for i in self._heap]
92+
return '>'.join(vals)
93+
94+
95+
if __name__ == '__main__':
96+
h = Heap([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
97+
h.heapify()
98+
print(h)
99+
print(h.heappop())
100+
print(h)
101+
h.heappush(3.5)
102+
print(h)
103+
h.heappush(0.1)
104+
print(h)
105+
h.heappush(0.5)
106+
print(h)
107+
print(h.heappop())
108+
print(h)

0 commit comments

Comments
 (0)