队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
首先了解 PriorityQueue(优先队列)
优先队列底层实现是一个堆,因为优先队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来是一个队列。
- 是一个基于优先级堆的无界优先级队列,底层实现是一棵完全二叉树
- 不允许使用
null
元素 - 不允许插入不可比较的对象,会导致
ClassCastException
。 - 优先级队列是无界的,但是有一个内部容量,默认容量为11,控制着用于存储队列元素的数组大小。它通常至少等于队列的大小。随着不断向优先级队列添加元素,其容量会自动增加
PriorityQueue
线程不安全,想线程安全用PriorityBlockingQueue
类
PriorityQueue 的长度问题
PriorityQueue
源码中有两个构造器,传一个整数参数进去,表示队列的长度,如果不传参,PriorityQueue
还有另一个构造器,直接调用静态全局常量 DEFAULT_INITIAL_CAPACITY
作为长度,默认值11,所以说优先队列的默认长度就是11;上面大顶堆中,就算是只有Comparator的匿名内部类,也可以调用DEFAULT_INITIAL_CAPACITY
设置长度,而 PriorityQueue
自己能自动扩容,所以如果没有特殊要求,是不需要管优先队列的长度的
实现
实现小顶堆
PriorityQueue<Integer> minheap = new PriorityQueue<>();
实现大顶堆
PriorityQueue<Integer> maxheap = new PriorityQueue<Integer>(new Comparator<>(){
@Override
public int compare(Integer i1,Integer i2){
return i2-i1;
}
});
可以看到,本质上,大顶堆是小顶堆调了 Comparator
进行了比较,实现匿名内部类
提到匿名内部类,就不得不提 lambda表达式,上面的代码就可以写成下面这样了
PriorityQueue<Integer> maxheap = new PriorityQueue<>((i1, i2) -> i2 - i1);
一行实现大顶堆
大顶堆和小顶堆的性质
堆是一颗完全二叉树,树中每个结点的值都比其左右孩子的值大或小。
父亲结点
大于等于左右孩子就是大顶堆(从大到小)
小于等于左右孩子就是小顶堆(从小到大)
(堆的这种特性非常的有用,堆常常被当做优先队列使用,因为可以快速的访问到“最重要”的元素)
常用方法
- add(E e)
- 添加元素到队尾,并调整堆结构
- remove()
- 返回并删除队头元素,并调整堆结构
- element()
- 返回队头元素(不删除)
- peek()
- 返回栈顶的元素(不删除)
- isEmpty()
- 判断队列是否为空
- size()
- 获取队列中元素个数
- clear()
- 清空队列
- contains(Object o)
- 判断队列中是否包含指定元素
- iterator()
- 迭代器