引言:
ArrayDeque,被称为“双端队列”,可以从两端进行插入或删除操作,当需要使用栈时,Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque,当需要使用队列时也可以使用ArrayDeque。
ArrayDeque类简介:
Deque的含义是“double ended queue”,即双端队列。它可以实现栈和队列的功能,存在以下这些方法的关系:
队列方法 双端队列方法
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()
栈方法 双端队列方法
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()
很明显的,ArrayDeque类就是一个实现了两头插入删除的队列。
ArrayDeque类属性:
主要属性如下所示,为存放元素的数组elements,头的索引位置head,尾的索引位置tail。
transient Object[] elements;
transient int head;
transient int tail;
ArrayDeque类的具体结构如下图所示:

ArrayDeque结构
ArrayDeque的数组是循环数组,就是可以head在后,tail在前。
ArrayDeque类的数组容量:
如下源码所示,ArrayDeque的数组容量由构造函数中调用allocateElements获取,而allocateElements方法的逻辑如下:
-1. 如果传入的容量参数numElements小于8,则使用8作为默认的容量。
-2.如果numElements>=8(且numElements<2的30次方),则取numElements的下一个2的指数的值作为容量。
-3.如果numElements>=2的30次,则取2的30次作为容量。
举个栗子:
numElements=9,
二进制为00000000 00000000 00000000 00001001
语句1后,结果为
00000000 00000000 00000000 00001101
语句2后,结果为
00000000 00000000 00000000 00001111
语句3,4,5执行后结果还是这个,就是15,再++就是16。
而numElements>=2的30次,则得到的结果为initialCapacity为-1,就是10000000 00000000 00000000 00000000,则右移一位,就是结果:01000000 00000000 00000000 00000000,2的30次。
private static final int MIN_INITIAL_CAPACITY = 8;
private void allocateElements(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
if (numElements >= initialCapacity) {
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);//1
initialCapacity |= (initialCapacity >>> 2);//2
initialCapacity |= (initialCapacity >>> 4);//3
initialCapacity |= (initialCapacity >>> 8);//4
initialCapacity |= (initialCapacity >>> 16);//5
initialCapacity++;
if (initialCapacity < 0)
initialCapacity >>>= 1;
}
elements = new Object[initialCapacity];
}
总结:ArrayDeque的容量总为2的指数,默认是8,构造函数时不必刻意传入2的指数,会自动计算。
如果传入的值>=2的30次,则使用最大容量2的30次。
ArrayDeque类的元素插入操作:
如下代码所示,为插入元素的操作,主要注意的是下标不能为越界。
这里使用(head - 1) & (elements.length - 1) 这样的方式来防止越界,elements.length - 1为低位全为1的二进制,与head-1做与运算,得到结果即可。
尾部插入操作也类似,都比较简单。
如下图所示:

addFirst操作
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
ArrayDeque类的扩容操作:
如下代码所示,扩容操作主要分两部分,容量申请为原来的两倍,将head右边的数据复制,将head左边的数据复制。
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 = a;
head = 0;
tail = n;
}
ArrayDeque类已基本介绍完毕,后续还有许多java容器的类,下次介绍。
ArrayDeque是Java中高效实现栈和队列功能的双端队列,其容量为2的指数,默认为8。插入操作通过循环数组防止越界,扩容时将原有元素复制到新的两倍容量数组中。ArrayDeque适用于需要快速在两端插入和删除的场景。
1185

被折叠的 条评论
为什么被折叠?



