优先队列
许多应用程序都需要处理有序的元素,但不一定要求它们全部有序,或是不一定要一次就将它们排序。很多情况下我们会收集一些元素,处理当前键值最大的元素,然后再收集更多的元素,再处理当前键值最大的元素,如此这般。例如,你可能由一台能够同时运行多个应用程序的电脑。这是通过为每个应用程序的事件分配一个优先级,并总是处理下一个优先级最高的事件来实现的。例如,绝大多数手机分配给来电的优先级都会比游戏程序的高。
在这种情况下,一个合适的数据结构应该支持两种操作:删除最大元素和插入元素。这种数据类型叫做优先队列。优先队列的使用和队列(删除最老的元素)以及栈(删除最新的元素)类似,但高效的实现它则更有挑战性。
在本节中,简单的讨论优先队列的基本表现形式(其一或者两种操作都能在线性时间内完成)之后,我们会学习基于二叉堆数据结构的一种优先队列的经典实现方法,用数组保存元素并按照一定条件排序,以实现高效的(对数级别的)删除最大元素和插入元素操作。
优先队列的一些重要的应用场景包括模拟系统,其中事件的键即为发生的时间,而系统需要按照时间顺序处理所有事件;任务调度,其中键值对应的优先级决定了应该首先执行哪些任务;数值计算,键值代表计算错误,而我们需要按照键值指定的顺序来修正它们。在第6章中我们会学习一个具体的例子,展示优先队列在粒子碰撞模拟中的应用。
通过插入一列元素然后一个个的删掉其中最小的元素,我们可以用优先队列实现排序算法。一种名为堆排序的重压排序算法也来自于基于堆的优先队列的实现。稍后再本书中我们会学习如何用优先队列构造其他算法。在第4章中我们可以看到优先队列如何恰到好处的抽象若干重要的图搜索算法。在第5章中,我们将使用本节所示的方法开发出一种数据压缩算法。这些只是优先队列作为算法设计工具所起到的举足轻重的作用的一部分例子。
一、API
表1:泛型优先队列的API
public class MaxPQ<Key extends Comparable<Key>> MaxPQ() 创建一个优先队列 MaxPQ(int max) 创建一个最大容量为max的优先队列 MaxPQ(Key[] a) 用a[]中的元素创建一个优先队列 void Insert(Key v) 向优先队列中插入一个元素 Key max() 返回最大元素 Key delMax() 删除并返回最大元素 boolean isEmpty() 返回队列是否为空 int size() 返回优先队列中的元素个数
-----