问题
打印机打印作业一般是放在队列中的。如果按照先来先打印的顺序,有一个100页的打印任务,那么会让后面短小的任务等待很长时间。更合理的做法也许是最后处理最耗时的打印任务,不管它是不是最后提交上来的。
在多用户操作系统中,操作系统让哪个程序使用CPU,是需要决定从队列里面选择的。一般做法是从队头获得程序,分配一定时间的时间片。如果执行完,从队列删除;如果没有执行完,插入队尾。这样处理的缺点是:一些很短小的程序需要花很长的时间才能执行完;有些比较重要的程序,不一定短小需要提前执行。
因此如果队列中的每个任务都有一个优先级,先执行优先级高的,就可以解决问题了。这样的队列称为优先队列(priority queue)。
优先队列定义
优先队列是要很小的代价完成插入和删除最小元素,两个操作的数据结构。
二叉堆
通常情况下的堆是指二叉堆。思路是每次插入都将最小元素(如果业务要求是找最小元素),放置在根节点,用O(logN)时间完成。可以用O(1)的时间获得最小元素。删除最小元素的时候除了返回最小元素的值,还将选取新的最小元素,用O(logN)的时间。
结构性质
二叉堆是一棵被完全填满的二叉树,有可能最底层元素不满,底层上的元素从左到右。(关键词:满二叉树、从左到右)
堆序性质
对最小堆而言:每一个节点X>父节点的值。最大堆相反。
操作
操作的时间复杂度小于O(logN)
insert
deleteMin
decreaseKey
increaseKey
delete
buildHeap
优先队列应用
选择问题
输入N个元素,查找第k小元素。解决思路1:将N个元素build一棵最小二叉堆,删除k次,得到第k小元素。解决思路2:前k个元素build一棵最大二叉堆,后面的每个元素读入的时候,与这里的最大元素比较,如果比最大元素小,则替换。
事件模拟
d堆
堆的分叉是d个,不仅仅是2个。有效降低堆的高度。实际中多用4-堆。
左势堆
二叉堆不能很方便的合并,所以提出了左式堆。左式堆是一个二叉堆。不同点是堆中每隔一节点X,左儿子的零路径长>=右儿子的零路径长,记为:nlp(left)>=nlp(right)。整棵树向左偏。
特殊操作
merge
时间复杂度 O(logN)
斜堆
二项队列
每次操作的最坏情形是O(logN),而插入操作平均花费常数时间。
一个二项队列是堆序的树的集合(简单的说就是树的集合)。二项队列中每一个高度的树只有一颗。
这里有
B0,B1,B2,B3,B4
。
Bk=Bk−1附加到另外一个Bk−1
。
高度为k的二项树恰好有
2k
个节点。我们就可以用二项队列表示任意一个优先队列。这与二进制表示一个数相同。例如6,的二进制是1101,
B0,B2,B3
三棵树可以表示容量为6的优先队列。
代码任务
1 二叉堆的实现
2 左势堆的合并
3 二项队列的实现