1.优先队列的概念
优先队列也是和栈/队列一样的缓存结构,但是它的独特点在于:每个进入缓存的元素都会附有一个数值,这个数值代表着取用时的先后顺序。
举一个简单的例子:我把附带优先数值2 3 1 5 4的元素,依次放入优先队列;尽管先放进去的是附加值为4的元素,但是它不会像队列一样,最先被取出;尽管最后放入的是附加值为2的元素,但是它也不会像栈一样,优先被弹出;它的正确取出方式是按照附加值从小到大(或者从大到小被取出)
2.优先队列的实现方式之一
我们可以用线性表去实现:每次把元素按照附加值,插入到线性表当中;但是这样插入的复杂度是O(n),取出为O(1)。
此类的实现方式简单;这里不必多言。
3.优先队列的实现方式之二
在学习了二叉树之后
我们可以利用完全二叉树去实现这种结构,完全二叉树的层次结构可以有效降低线性表的线性插入复杂度。
具体我们可以做如下分析:
1.利用二叉树实现堆是基础
堆的概念:一个 父节点必须小于(大于)子节点的 完全二叉树。(从每一个叶节点向上到根节点都是有序的)
2.在堆中插入元素
插入元素:① 先放在原来堆的末尾;当这个新添元素的父元素序号( (p-1)//2 )大于0的时候
② 然后执行向上筛选
最后 当这个父亲元素序号 == 0 时:执行最后一次向上筛选。
附:向上筛选:
向上筛选每次只要和父节点比就行(向下筛选要和两个子节点相比),具体如下
首先:输入向上筛选的起始元素,在父节点序号大于0的时候;比较父子节点大小,满足子小于父节点,调换;更新起始元素;回到首先处;当起始元素更新到它的父元素的序号是0的时候;执行最后一次向上筛选;结束。
3.从完全二叉树中建堆
①可以利用2的方法,将完全二叉树的元素一一插入,从而建立堆;但是这样复杂度略高
②在重整完全二叉树建堆
先找到原始完全二叉树的最后一个元素;再找它的父节点(son//2 -1);从这个父节点向下筛选;然后找这个父节点所在的序号的前一个元素;向下筛选;就这样直到序号为0时结束。
附:向下筛选:
首先,我们已经有了这个父节点的序号;在保证这个父节点的两个子节点都在的情况下 找到这个父节点的两个子节点;再将父节点和这两个子节点比较,把最小的放在父节点的位置;更新这个父节点,使这个父节点进入子代;再回到开始的地方。当这个父节点的一个子节点不在了;比较父节点和唯一的子节点;结束整个向下筛选;当这个父节点两个子节点都不在了;结束整个向下筛选。
小结:本节逻辑完全正确,具体代码实现需要注意的细节也在代码内标注:见文章底部
4.删除元素
① 删除根节点;然后把末尾的元素放到根节点的位置
② 做一次向下筛选
5. 优先队列API
1、heappush(heap, x):向堆中添加元素
from heapq import *
heap = [] for i in range(3):
heappush(heap, i)
print(heap) #[0, 1, 2]
heappush(heap, 0.5)
print(heap) #[0, 0.5, 2, 1]
heappush(heap, 1.5)
print(heap) #[0, 0.5, 2, 1, 1.5]
2、heappop(heap):弹出堆中最小的元素,并且维持剩余元素的堆结构。
3、heapify(heap):将列表转换为堆。
4、heapreplace(heap, x):弹出堆中最小的元素,然后将新元素插入。
5、nlargest(n, iter)、nsmallest(n, iter):用来寻找任何可迭代对象iter中的前n个最大的或前n个最小的元素。