介绍
优先队列是一种抽象数据类型,表示了一组值和对这些值的操作。优先队列最重要的操作就是删除最大元素和插入元素。泛型优先队列的API:
public class MaxPQ<key extends Comparable |
|
---|---|
MaxPQ | 创建一个优先队列 |
MaxPQ(int max) | 创建一个初识容量为max的优先队列 |
MaxPQ(key[] a) | 用a[]中的元素创建一个一个优先队列 |
void insert() | 向优先队列中插入一个元素 |
key max() | 返回最大元素 |
key delMax() | 删除并返回最大元素 |
boolean isEmpty() | 返回队列是否为空 |
int size() | 返回优先队列中的元素个数 |
优先队列的调用示例:
问题:从输入的N个字符串中找出M个最大元素,前提是输入量非常巨大。
构造一个用数字作为键的优先队列,当优先队列的大小超过M时就删掉其中最小的元素。处理完所有交易。优先队列中存放的以降序排列的最大的M个交易,然后将该段代码放在一个栈中,遍历这个栈以颠倒它们顺序,从而将它们按降序打印出来。
1 | public class TopM { |
实现
下面使用有序和无序的数组以及链表实现优先队列。
数组实现(无序)
insert()方法的代码和栈的push()方法一样。实现删除最大元素,添加一段类似选择排序的内循环的代码,将最大元素和边界元素交换然后删除它,和栈的pop()方法实现一样。同样,可以添加调整数组大小的代码来保证数据结构中至少含有四分之一的元素而永远不会溢出。(详见栈)。
1 | /** |
数组实现(有序)
在insert()方法中添加代码,将所有较大的元素向右边移动一格以使数组保持有序(和插入排序一样)。这样,最大的元素总会在数组的一边,优先队列的删除最大元素操作就和栈的pop()操作一样。
1 | /** |
链表实现
可以用基于链表的下压栈的代码实现,然后可以选择修改pop()来找到并返回最大元素,或是修改push()来保证所有元素为逆序并与pop()来删除并返回链表的首元素(最大元素)。
总结
使用无序序列实现优先队列是惰性方法,使用有序序列实现优先队列是积极方法。
实现栈或是队列与实现优先队列的最大不同在于对性能的要求。对于栈和队列,我们的实现能在常数时间内完成所有操作;而对于优先队列,上面的初级实现,插入元素和删除最大元素这两个操作之一在最坏情况下需要线性时间完成。
优先队列的各种实现在最坏情况下运行时间的增长数量级:
数据结构 | 插入元素 | 删除最大元素 |
---|---|---|
有序数组 | N | 1 |
无序数组 | 1 | N |
堆 | logN | logN |
理想情况 | 1 | 1 |