优先队列
听这个名字就能知道,优先队列也是一种队列,只不过不同的是,优先队列的出队顺序是按照优先级来的;在有些情况下,可能需要找到元素集合中的最小或者最大元素,可以利用优先队列ADT来完成操作,优先队列ADT是一种数据结构,它支持插入和删除最小值操作(返回并删除最小元素)或删除最大值操作(返回并删除最大元素); 这些操作等价于队列的enQueue和deQueue操作,区别在于,对于优先队列,元素进入队列的顺序可能与其被操作的顺序不同,作业调度是优先队列的一个应用实例,它根据优先级的高低而不是先到先服务的方式来进行调度;
如果最小键值元素拥有最高的优先级,那么这种优先队列叫作升序优先队列(即总是先删除最小的元素),类似的,如果最大键值元素拥有最高的优先级,那么这种优先队列叫作降序优先队列(即总是先删除最大的元素);由于这两种类型时对称的,所以只需要关注其中一种,如升序优先队列;
优先队列的应用
- 数据压缩:赫夫曼编码算法;
- 最短路径算法:Dijkstra算法;
- 最小生成树算法:Prim算法;
- 事件驱动仿真:顾客排队算法;
- 选择问题:查找第k个最小元素;
- 等等等等....
优先队列的实现比较
二叉堆
基于二叉堆实现的简单降序优先队列
package datastructure.queue; import java.util.Arrays; /** * 降序优先队列 */ public class MaxPriorityQueue { private int size = 0; private int[] array; public MaxPriorityQueue() { array = new int[32]; } public MaxPriorityQueue(int size) { array = new int[size]; } public MaxPriorityQueue(int[] array) { this.size = array.length; this.array = array; synchronized (this.array) { for (int parentIndex = 0; parentIndex < this.size / 2; parentIndex++) { int childIndex = 2 * parentIndex + 1; if (childIndex + 1 < this.size && array[childIndex] < array[childIndex + 1]) { childIndex++; } if (array[childIndex] > array[parentIndex]) { int temp = array[parentIndex]; array[parentIndex] = array[childIndex]; array[childIndex] = temp; } } } } public void add(int element) { if (size >= array.length) { System.out.println("resize"); resize(); System.out.println("resize over"); } array[size++] = element; upAdjust(); } public int pop() { if (size < 1) { throw new RuntimeException("the queue is empty!"); } int head = array[0]; array[0] = array[--size]; downAdjust(); return head; } private void downAdjust() { int parentIndex = 0; int temp = array[parentIndex]; int childIndex = 2 * parentIndex + 1; while (childIndex < this.size) { if (childIndex + 1 < this.size && array[childIndex] < array[childIndex + 1]) { childIndex++; } if (array[childIndex] > temp) { array[parentIndex] = array[childIndex]; parentIndex = childIndex; childIndex = 2 * parentIndex + 1; } else { break; } } array[parentIndex] = temp; } private void upAdjust() { int childIndex = this.size - 1; int parentIndex = (childIndex - 1) / 2; int temp = this.array[childIndex]; while (childIndex > 0 && temp > array[parentIndex]) { array[childIndex] = array[parentIndex]; childIndex = parentIndex; parentIndex = (childIndex - 1) / 2; } this.array[childIndex] = temp; } private void resize() { int newSize = this.size * 2; this.array = Arrays.copyOf(this.array, newSize); } public int size() { return this.size; } public static void main(String[] args) { int[] array = {1, 2, 9, 4, 6, 7, 8, 3, 0, 5}; System.out.println("原始数组:" + Arrays.toString(array)); MaxPriorityQueue queue = new MaxPriorityQueue(array); System.out.println("准备添加"); queue.add(14); queue.add(11); queue.add(20); queue.add(12); System.out.println("添加完"); int size = queue.size(); for (int i = 0; i < size; i++) { System.out.println(queue.pop()); } } }
java 中的优先队列
在Java中也实现了自己的优先队列java.util.PriorityQueue,与我们自己写的不同之处在于,Java中内置的为最小堆,然后就是一些函数名不一样,底层还是维护了一个Object类型的数组,大家可以戳戳看有什么不同,另外如果想要把最小堆变成最大堆可以给PriorityQueue传入自己的比较器

