Python自定义二叉堆类

二叉堆有两种:最小成员key排在队首的称为“最小堆(min heap)”;最大key排在队首的是“最大堆(max heap)”,这是一种优先队列的实现方式。

优先队列的出队(Dequeue)操作和队列一样,都是从队首出队。但在优先队列内部,数据项的次序是由它们的“优先级”来确定的:有最高优先级的数据项排在队首,而优先级最低的数据项则排在队尾。这样,优先队列的入队(Enqueue)操作就需要将数据项挤到队列前方。

完全二叉树:指每个内部节点都有两个子节点,最多可有一个节点例外。

如果完全树的节点在列表中的位置为p(p>0),那么其左子节点的位置就为2p,右子节点的位置就为2p+1。

找任意节点的父节点的方法:若节点在列表中的位置为n,那么其父节点的位置就是n//2。

堆次序:是指堆中任意一个节点x,其父节点p中的key(节点值)均小于或等于x中的key。

# 自定义最小堆类
class BinHeap(object):
	# 构造二叉堆
	def __init__(self):
		# 表首下标为0的项并没有用到,但为了后面代码可以用到简单的整数乘除法,仍保留它
		self.heapList = [0]			
		self.currentSize = 0

	# 上浮函数,i为节点位置,判断新节点是否比父节点小,若小则新节点交换上浮以保证堆次序
	def percUp(self, i):
		while i // 2 > 0:				#若父节点的位置大于0,则循环
			if self.heapList[i] < self.heapList[i // 2]:	#若子节点值小于父节点值,则交换位置
				self.heapList[i], self.heapList[i // 2] = self.heapList[i // 2], self.heapList[i]
			i = i // 2 					#更新当前节点位置,判断是否需要继续上浮

	# 插入函数,添加新节点
	def insert(self, k):
		self.heapList.append(k)			#向堆中插入新节点
		self.currentSize += 1 			#更新新节点位置
		self.percUp(self.currentSize)	#检查新节点是否需要上浮,以维持堆次序

	# 下沉函数,i为节点位置,判断子节点是否比父节点小,若小则父节点交换下沉以保证堆次序
	def percDown(self, i):
		# 若i*2<=当前节点位置(最后一个节点),说明待测节点有子节点,则循环
	    while (i * 2) <= self.currentSize:	
	        mc = self.minChild(i)		#获取i的最小子节点位置
	        if self.heapList[i] > self.heapList[mc]:	#若i的值>其最小子节点值,则交换位置
	        	self.heapList[i], self.heapList[mc] = self.heapList[mc], self.heapList[i]
	        i = mc 						#更新待检测下沉节点位置,判断是否需要继续下沉
	
	# 获取最小子节点位置
	def minChild(self, i):
	    if i * 2 + 1 > self.currentSize:#i的右子节点位置>当前节点位置(最后一个节点),则
	        return i * 2 				#返回左子节点位置,因为i没有右子节点
	    else:							#若i有右子节点,则
	        if self.heapList[i * 2] < self.heapList[i * 2 + 1]:	#若i的左子节点值<右子节点值,则
	            return i * 2 			#返回左子节点位置
	        else:
	            return i * 2 + 1 		#返回右子节点位置

	# 删除最小节点
	def delMin(self):
	    retval = self.heapList[1]		#获取最小节点,即根节点
	    # 以下4行代码是为了维持堆结构和堆次序
	    self.heapList[1] = self.heapList[self.currentSize]	#将当前节点,即最后一个节点赋值给根节点,不能直接删除根节点,因为要维持堆结构
	    self.heapList.pop()				#删除堆最后一个节点,因为此节点值已交换给了根节点
	    self.currentSize -= 1 			#当前节点位置减1,因为删除了一个节点
	    self.percDown(1)				#检查新的根节点是否需要下沉,以维持堆次序
	    return retval 					#返回删除的最小节点

	# 无序列表构建二叉堆
	def buildHeap(self, alist):
		self.currentSize = len(alist)	#获取列表最后一个位置
		self.heapList = [0] + alist[:]	#列表0位置添加0元素,便于后续计算
		i = len(alist) // 2 			#获取最后一个节点的父节点位置
		while i > 0:
			self.percDown(i)			#判断父节点是否需要下沉
			i = i -1 					#将待检测节点位置更新为上一个节点位置

bh = BinHeap()							#实例化最小堆类
bh.buildHeap([9,5,6,2,3])				#无序列表构建最小堆
print(bh)
print(bh.delMin())						#删除当前最小节点
print(bh.delMin())
print(bh.delMin())
bh.insert(7)							#添加新节点
print(bh.delMin())
print(bh.delMin())

结果为:

<__main__.BinHeap object at 0x00000000026FF630>
2
3
5
6
7

猜你喜欢

转载自blog.csdn.net/qq_38882327/article/details/89327804