实现堆的函数,像heapq的库一样,对列表进行操作。(小根堆)
明确二叉树的标号关系
数组中,根节点索引为0.
索引为
i
d
x
idx
idx的节点,左子节点为
2
∗
i
d
x
+
1
2 * idx + 1
2∗idx+1,右子节点为
2
∗
i
d
x
+
2
2 * idx + 2
2∗idx+2. 反过来,一个节点下标为
i
d
x
idx
idx,它的父节点下标为
(
i
d
x
−
1
)
/
/
2
(idx - 1) // 2
(idx−1)//2.
例如,索引为2的节点,左子节点和右子节点的索引分别为5和6.
_siftdown和_siftup
实现堆,最关键的是对元素的移动(上移/下移)。所有函数都是基于这两种操作完成的。
down指的是从堆底到堆顶的过程,指的是元素的索引小了,down了。反过来,up就是堆顶到堆底的过程,索引大了,up了。
_siftdown函数:将元素向堆顶移动到符合条件为止
'''将idx索引位置的元素往堆顶移动。startidx指堆顶的索引'''
def _siftdown(heap, startidx, idx):
newitem = heap[idx] #先保存下
'''逐步与父节点比'''
while startidx < idx:
parentidx = (idx - 1) >> 1 #
parent = heap[parentidx]
'''这个元素比父节点小,就把父节点往下蹿一个'''
if newitem < parent:
heap[idx] = parent #parent值向堆底移动
idx = parentidx
else:
break
'''while循环结束后,idx就处在上一个父节点往下蹿之后空出来的位置,把之前保存的填进去就完成了'''
heap[idx] = newitem
!!!重点,_siftup虽然将元素向堆底移动了,但是如果只移动的话,不一定符合堆的性质。所以_siftup函数要包含_siftdown函数,利用_siftdown函数再将元素向堆顶移动,找到其合适的位置。
这段代码的最后一句注释要仔细看
'''idx位置的元素往堆底移动'''
def _siftup(heap, idx):
endidx = len(heap) - 1
startidx = idx
newitem = heap[idx]
'''先保存下,再把子节点往上提'''
child_idx = 2 * idx + 1 #初始为左子节点
while child_idx <= endidx:
'''共有两个子节点,应该选较小的往上提'''
rightchild_idx = child_idx + 1
if rightchild_idx <= endidx and heap[rightchild_idx] <= heap[child_idx]:
child_idx = rightchild_idx
heap[idx] = heap[child_idx]
idx = child_idx
child_idx = 2 * idx + 1
'''while结束时,idx停在最后一个子节点向上蹿,空出来的位置'''
heap[idx] = newitem
'''前面节点往上蹿的时候,newitem从来都没和任何元素比较过,最后需要再尝试把它往堆顶移,帮它找到正确的位置'''
_siftdown(heap, startidx, idx)
将list初始化为堆 heapify操作
过程:把所有非叶子节点,逐个_siftup
def heapify(heap):
n = len(heap)
'''
二叉树最后一个的节点,在数组中的下标为n - 1,它的父节点,也是二叉树按顺序的最后一个父节点,
下标就是n - 2 // 2, 即n // 2 - 1
要从后往前,逐个处理
'''
for i in range(n // 2 - 1, -1, -1):
_siftup(heap, i)
push操作
过程:将新元素添加到最末尾,再向堆顶移动该元素。
def heappush(heap, x):
heap.append(x)
_siftdown(heap, 0, len(heap) - 1)
pop操作
过程:思想是将堆顶元素heap[0]取出,再将堆末尾元素补到堆顶,再将这个元素_siftup。实现起来,先利用列表的pop函数获得最后一个元素,再将heap[0]作为返回值暂时保存下来,再将最后一个元素覆盖到heap[0],再_siftup.
def heappop(heap):
last = heap.pop()
#heap为空直接报错
'''先pop后,heap可能变成空了
如果不空,就将heap[0]作为返回值
若是空了,那就last直接就是返回值了
'''
if heap:
ans = heap[0]
heap[0] = last
_siftup(heap, 0)
return ans
return last