Python小根堆的实现

实现堆的函数,像heapq的库一样,对列表进行操作。(小根堆

明确二叉树的标号关系

数组中,根节点索引为0.
索引为 i d x idx idx的节点,左子节点为 2 ∗ i d x + 1 2 * idx + 1 2idx+1,右子节点为 2 ∗ i d x + 2 2 * idx + 2 2idx+2. 反过来,一个节点下标为 i d x idx idx,它的父节点下标为 ( i d x − 1 ) / / 2 (idx - 1) // 2 (idx1)//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	
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值