优先队列中的每个元素都有对应的优先级,优先级最高的元素最先获得服务,优先级相同的元素按照其在优先队列中的顺序得到服务。
操作
- 插入带有优先级的元素
- 取出具有最高优先级的元素
- 查看最高优先级的元素
其它可选的操作:
- 检查优先级高的一批元素
- 清空优先队列
- 批插入一批元素
- 合并多个优先队列
- 调整一个元素的优先级
实现
初级实现
使用有序数组,插入时排序,插入效率为,取出效率为
import Queue from "./Queue";class QueueElement {constructor(element, priority) {this.element = element;this.priority = priority;}}export class PriorityQueue extends Queue {constructor() {super();}// euqueue 入队// 重写enqueue,需要加入priorityenqueue(element, priority) {// 根据传入元素,创建QueueElement对象const queueElement = new QueueElement(element,priority);// 判断队列是否为空if (this.isEmpty()) {// 如果是空队列,就不管优先级了,直接添加this.items.push(queueElement);} else {// 定义变量记录是否添加新元素let added = false;for(let i = 0; i < this.items.length; i++) {// 让新加入的元素进行优先级比较,priority越小,优先级越大if (queueElement.priority < this.items[i].priority) {this.items.splice(i,0, queueElement);added = true;break;}}// 如果队列中元素都被遍历了,说明优先级最小,插到队列末尾if (!added) {this.items.push(queueElement);}}}// dequeue 出队,从队列中删除前端元素,返回被删除的元素,因为已经插入时就排好序了,所以此时就无需排序dequeue() {return super.dequeue();}// peek 查看队列前端元素peek() {return super.peek();}// isEmpty 查看队列是否为空isEmpty() {return super.isEmpty();}// size 查看队列中元素个数size() {return super.size();}// clear 清除队列中的元素clear() {return super.clear();}// toString 将队列中元素以字符串形式输出toString() {let result = '';for (let item of this.items) {result += item.element + '-' + item.priority;}return result;}}
典型实现
出于性能考虑,优先队列用堆)来实现,具有O(log n)时间复杂度的插入元素性能,O(n)的初始化构造的时间复杂度。如果使用自平衡二叉查找树,插入与删除的时间复杂度为O(log n),构造二叉树的时间复杂度为O(n log n)。
从计算复杂度的角度,优先级队列等价于排序算法。
有一些特殊的堆)为优先队列的实现提供了额外的性能:二叉堆的插入与提取操作的时间复杂度为O(log n),并可以常量时间复杂度的peek操作。二项堆提供了几种额外操作。斐波那契堆的插入、提取、修改元素优先级等操作具有分摊常量时间复杂度,[1],但删除操作的时间复杂度为O(log n)。Brodal queue具有最糟糕情况下的常量复杂度但算法相当复杂因而不具有实用性。
对于整型、浮点型等具有有限值域的元素的数据类型,优先队列有更快的实现。
