概要
Queue
是继承于Collection
的接口,是FIFO的单端队列。PriorityQueue
实现了Queue
,是优先队列。
Deque
是继承于Queue
的子接口,是双端队列。LinkedList
实现了Deque
,是双向链表。
ArrayQueue
实现了Deque
,是用数组表示的小顶堆。
一、Queue(interface)
是FIFO的接口,只有:添加元素到队尾、取队首元素并删除、取队首元素但不删除。
这些方法以两种形式存在:(1)操作失败时抛出异常;(2)操作失败时返回特殊值(false或null)。
要避免把null
加入队列中。因为poll()
方法返回null
时,不确定是取到了null
元素还是队列为空返回的null
特殊值。
二、PriorityQueue(class)
1、优先队列、排序
PriorityQueue
实现了一个优先队列:从队首获取元素时,总是获取优先级最高的元素。
PriorityQueue
默认按元素比较的顺序排序(必须实现 Comparable
接口),也可以通过 Comparator
自定义排序算法(元素就不必实现 Comparable
接口)。
1 | Queue<String> p = new PriorityQueue<>();//String元素实现了 Comparable 接口 |
2、底层结构:数组表示的堆
PriorityQueue
底层数据结构是数组表示的小顶堆transient Object[] queue;
。
二叉堆用数组来表示:父子节点下标关系为:
1 | int leftNo = (parentNo << 1) + 1; //leftNo = parentNo*2+1; |
3、方法
add(E e)
/offer(E e)
:新加入的元素可能会破坏小顶堆的性质,需要向上调整。不允许加入null
元素
poll()
/remove(Object o)
:删除堆顶或其他位置元素,也需要向下调整。
4、扩容
三、Deque(interface)
Deque
接口扩展自Queue
接口,实现了一个双端队列,可以当作栈使用,也可以当作队列使用。
使用Deque
,最好是明确调用 offerLast()
/offerFirst()
或者 pollFirst()
/pollLast()
方法,更能直观表明操作队首还是队尾。
Deque
是一个接口,它的实现类有 ArrayDeque
和 LinkedList
。
四、ArrayDeque(class)
数组方式实现的双端队列。
1、特点:
- 底层由数组实现,没有容量限制,根据需要扩容
- 不是线程安全的,在没有外部同步的情况下,不知道多线程并发访问
- 不允许放入
null
元素 - 用作堆栈时,比
Stack
快;用作队列时,比LinkedList
快
2、属性:head、tail
底层数据结构为数组,最小长度为8,默认长度为16,若构造时指定初始长度,调用方法使长度始终为2的幂。
ArrayDeque中数组是当做环形/循环数组来使用的。
head
指向队首第一个有效元素(也是removeFirst/pollFirst删除的元素)。
tail
指向队尾第一个可以插入元素的空位(也是addLast/offerLast加入元素的位置)。
1 | transient Object[] elements; |
3、方法:addFirst()
/offerFirst()
,addLast()
/offerLast()
。
addFirst(E e)
是在队列的首端(即head
的前面)加入元素。
addLast(E e)
是在队列的尾端(即tail
位置)加入元素。
1 | public void addFirst(E e) { |
- 1)新加入的元素数组下标为:
(head - 1) & (elements.length - 1)
,可以解决head-1
下标越界问题。
不是直接通过head-1
,tail-1
等直接计算来更新head
/tail
,而是与element.length - 1
做位与运算,解决下标越界问题。(element.length
为2的幂)
// todo head-1为-1时,位与运算
- 2)判断扩容是在元素加入之后,因为 tail 指向队尾可插入的空位,保证数组elements至少有一个空位。
3、扩容
扩容是发生在元素插入之后,若head == tail
(此时无空位),实现扩容两倍doubleCapacity()
。
1 | private void doubleCapacity() { |
五、LinkedList
1 | public class LinkedList<E> |
- 底层结构为双向链表。
- 既实现了
List
,也实现了Deque
。
六、用作:堆栈、队列
ArrayDeque
和LinkedList
都实现了队列Deque
接口,可用作堆栈,也可用作队列。
ArrayDeque
用作堆栈时,比Stack
快;用作队列时,比LinkedList
快
1、Stack
继承自Vector
(Vector是线程安全的List),已经过时。
2、用作栈的方法名称:
add/remove
等方法操作失败时抛出异常;push/pop/peek/offer/poll
等方法操作失败时返回特殊值(false或null)。
push(E e)
/addFirst()
pop()
/removeFirst()
peek()
3、用作队列的方法名称:
单端队列
Queue
offer(E e)/add(E e)
:添加元素到队尾poll()/remove()
:取队首元素并删除peek()/element()
:取队首元素但不删除
双端队列
Deque
offerFirst()
/addFirst()
,offerLast()
/addLast()
pollFirst()
/removeFirst()
,pollLast()
/removeLast()
peekFirst()
/getFirst()
,peekLast()
/getLast()