队列:FIFO,先进先出
优先队列:队列中每个元素都分配一个优先权值,队列的出队顺序按照优先权值来划分,高者优先或者低者优先。这样优先队列必须有两个基本操作:入队和(按照优先权值)出队(以优先级高的先出来),简单点说就是插入或者删除元素的时候,元素自动排序,实现原理二叉堆的操作
应用:打印机的任务调度和操作系统的进程调度。
优先想到的就是用排序函数和队列的一些简单方法来实现优先队列。但是在列表中插入一个数据的复杂度是O(n),因为你插入的时候要移动数据,列表的排序复杂度是O(nlogn),我们可以用别的方法来降低复杂度。比如:二叉堆实现优先队列,二叉堆可以将复杂度保持在O(logn)。置于为什么请看二叉堆的结构。
特殊的二叉树,对一般的二叉树提出了结构性和堆序性的要求
结构性:二叉堆是一个完全二叉树(除最后一层每层结点达到最大值,最后一层叶子节点连续集中在左侧)
堆序性:大根堆:所有结点值大于其后裔结点值 。 (父大于子)
小根堆:所有节点值均小于其后裔结点值。(父小于子)
使用单列表实现二叉树,对于结点列表中下标为p,那么左子节点为2p,右节点2p+1
举个例子(如图):
【注意】数组的第一个索引0空着不用,通常我们把第一个元素设置为0,结点i的儿子是2i和2i+1
class BinHeap:
def __init__(self):
self.heapList=[0]
self.currentSize=0#完全树的单列表表示,以及下标,记录堆的大小
def buildHeap(self,alist):#从列表生成二叉堆
i = len(alist)//2 # 优化(至于为什么暂时没搞懂)
self.currentSize=len(alist)
self.heapList = [0]+alist[:]#i永远不会得0,不会访问到这个元素列表从0访问,树从1,添加0后保证了树的性质
while(i>0):
self.percDown(i)
i-=1
def percDown(self,i):#下沉
while (i*2)<=self.currentSize:#循环下沉直到结束
mc = self.minChild(i)#记录两个孩子的最小值的位置mc
if self.heapList[i]>self.heapList[mc]:#比较孩子和父亲的大小
tmp = self.heapList[i]#如果父亲大,交换使得大数下沉
self.heapList[i]=self.heapList[mc]
self.heapList[mc] = tmp
i=mc
def minChild(self,i):#返回两个子节点的最小值的位置
if i*2+1>self.currentSize:
return i*2 #和percdown中的while条件相呼应,说明结束
else:
if self.heapList[i*2]<self.heapList[i*2+1]:
return i*2
else:
return i*2+1
def delMin(self):#返回堆中的最小项同时删除
retval = self.heapList[1]#记录最小值
self.heapList[1] = self.heapList[self.currentSize]#将最后一个值放在根部
self.currentSize-=1
self.heapList.pop()#结点释放掉
self.percDown(1)#根部元素需要调整为满足堆得性质
return retval
def percUP(self,i):#小数上浮,i为下标
while i//2>0:#不断上浮
if self.heapList[i]<self.heapList[i//2]:#新节点小于父子节点
tmp = self.heapList[i//2]
self.heapList[i//2] = self.heapList[i]
self.heapList[i] = tmp #交换
i=i//2#继续和上面的比较
def insert(self,k):#插入结点的值
self.heapList.append(k)
self.currentSize+=1
self.percUP(self.currentSize)#调整堆得次序小数上浮
'''
coding=utf-8
'''
class BinHeap:
def __init__(self):
self.heapList=[0]
self.currentSize=0#完全树的单列表表示,以及下标,记录堆的大小
def percUP(self,i):#小数上浮,i为下标
while i//2>0:#不断上浮
if self.heapList[i]<self.heapList[i//2]:#新节点小于父子节点
tmp = self.heapList[i//2]
self.heapList[i//2] = self.heapList[i]
self.heapList[i] = tmp #交换
i=i//2#继续和上面的比较
def insert(self,k):#插入结点的值
self.heapList.append(k)
self.currentSize+=1
self.percUP(self.currentSize)#调整堆得次序小数上浮
def percDown(self,i):#下沉
while (i*2)<=self.currentSize:#循环下沉直到结束
mc = self.minChild(i)#记录两个孩子的最小值的位置mc
if self.heapList[i]>self.heapList[mc]:#比较孩子和父亲的大小
tmp = self.heapList[i]#如果父亲大,交换使得大数下沉
self.heapList[i]=self.heapList[mc]
self.heapList[mc] = tmp
i=mc
def minChild(self,i):#返回两个子节点的最小值的位置
if i*2+1>self.currentSize:
return i*2 #和percdown中的while条件相呼应,说明结束
else:
if self.heapList[i*2]<self.heapList[i*2+1]:
return i*2
else:
return i*2+1
def delMin(self):#返回堆中的最小项同时删除
retval = self.heapList[1]#记录最小值
self.heapList[1] = self.heapList[self.currentSize]#将最后一个值放在根部
self.currentSize-=1
self.heapList.pop()#结点释放掉
self.percDown(1)#根部元素需要调整为满足堆得性质
return retval
def buildHeap(self,alist):#从列表生成二叉堆
i = len(alist)//2 # 优化(至于为什么暂时没搞懂)
self.currentSize=len(alist)
self.heapList = [0]+alist[:]#i永远不会得0,不会访问到这个元素列表从0访问,树从1,添加0后保证了树的性质
while(i>0):
self.percDown(i)
i-=1
#举个例子感受一下吧
bh = BinHeap()
bh.buildHeap([9,5,6,2,3])
print(bh.delMin())
print(bh.delMin())
print(bh.delMin())
print(bh.delMin())
print(bh.delMin())
【注】所有的问题都出在写代码上,不写代码逼事没有(所以有问题看注释,哈哈)