Queue除了前面介绍的实现外,还有一种双向的Queue实现Deque。这种队列允许在队列头和尾部进行入队出队操作,因此在功能上比Queue显然要更复杂。下图描述的是Deque的完整体系图。需要说明的是LinkedList也已经加入了Deque的一部分(LinkedList是从jdk1.2 开始就存在数据结构)。
Deque在Queue的基础上增加了更多的操作方法。
从上图可以看到,Deque不仅具有FIFO的Queue实现,也有FILO的实现,也就是不仅可以实现队列,也可以实现一个堆栈。
同时在Deque的体系结构图中可以看到,实现一个Deque可以使用数组(ArrayDeque),同时也可以使用链表(LinkedList),还可以同实现一个支持阻塞的线程安全版本队列LinkedBlockingDeque。
1、ArrayDeque实现Deque
对于数组实现的Deque来说,数据结构上比较简单,只需要一个存储数据的数组以及头尾两个索引即可。由于数组是固定长度的,所以很容易就得到数组的头和尾,那么对于数组的操作只需要移动头和尾的索引即可。
特别说明的是ArrayDeque并不是一个固定大小的队列,每次队列满了以后就将队列容量扩大一倍(doubleCapacity()),因此加入一个元素总是能成功,而且也不会抛出一个异常。也就是说ArrayDeque是一个没有容量限制的队列。
同样继续性能的考虑,使用System.arraycopy复制一个数组比循环设置要高效得多。
1.1、ArrayDeque的源码解析
- //数组双端队列ArrayDeque的源码解析
- public
class ArrayDeque extends AbstractCollection implements Deque, Cloneable, Serializable{ -
-
private transient E[] elements; -
-
private transient int head; -
-
private transient int tail; -
-
private static final int MIN_INITIAL_CAPACITY = 8; -
// ****** Array allocation and resizing utilities ****** -
-
private void allocateElements(int numElements) { -
int initialCapacity = MIN_INITIAL_CAPACITY; -
if (numElements >= initialCapacity) { -
initialCapacity = numElements; -
initialCapacity |= (initialCapacity >>> 1); -
initialCapacity |= (initialCapacity >>> 2); -
initialCapacity |= (initialCapacity >>> 4); -
initialCapacity |= (initialCapacity >>> 8); -
initialCapacity |= (initialCapacity >>> 16); -
initialCapacity++; -
if (initialCapacity < 0) // Too many elements, must back off -
initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements -
} -
elements = (E[]) new Object[initialCapacity]; -
} -
-
private void doubleCapacity() { -
assert head == tail; -
int p = head; -
int n = elements.length; -
int r = n - p; // number of elements to the right of p -
int newCapacity = n << 1; -
if (newCapacity < 0) -
throw new IllegalStateException("Sorry, deque too big"); -
Object[] a = new Object[newCapacity]; -
System.arraycopy(elements, p, a, 0, r); -
System.arraycopy(elements, 0, a, r, p); -
elements = (E[])a; -
head = 0; -
tail = n; -
} -
-
private T[] copyElements(T[] a) { -
if (head < tail) { -
System.arraycopy(elements, head, a, 0, size()); -
} else if (head > tail) { -
int headPortionLen = elements.length - head; -
System.arraycopy(elements, head, a, 0, headPortionLen); -
System.arraycopy(elements, 0, a, headPortionLen, tail); -
} -
return a; -
} -
-
public ArrayDeque() { -
elements = (E[]) new Object[16]; -
} -
-
public ArrayDeque(int numElements) { -
allocateElements(numElements); -
} -
-
public ArrayDeque(Collection