1. 定义
ArrayDeque:基于数组的双端队列
2. 特点
- 用作栈时,比Stack快;用作队列时,比LinkedList快。
- ArrayDeque的大多数操作运行时的时间分摊下来都是常数时间(O(1))。除了remove,removeFirstOccurrence,removeLastOccurrence,contains,iterator.remove() and the bulk operations,这些操作的时间复杂度是O(n)。
- 非线程安全
3. 基本功能
属性:
transient Object[] elements;
//用于进行remove()或pop()操作时的索引;当队列为空时,head==tail(任意值)。
transient int head;
//下一个元素被添加到的位置,用于进行addLast(E),add(E),push(E)
transient int tail;
//最小初始化容量(必须是2的指数)
private static final int MIN_INITIAL_CAPACITY = 8;
方法:
- allocateElements(int numElements) 把参数转成2的指数,然后new Object数组。
private void allocateElements(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
// Find the best power of two to hold elements.
// Tests "<=" because arrays aren't kept full.
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 = new Object[initialCapacity];
}
- doubleCapacity()
把deque的数组容量扩充为2倍大。只有当满了的时候才执行,也就是head和tail变得相等时。
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];
//先把从p到最后的部分copy至新数组中,再把前半部分copy至新数组。
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = a;
head = 0;
tail = n;
}
- copyElements(T[] a) 把数组拷贝到另一个特定的数组中
- 构造函数
public ArrayDeque()
public ArrayDeque(int numElements)
public ArrayDeque(Collection<? extends E> c) - addFirst(E e)
在双端队列的前端插入元素
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
//如果head==tail,就进行扩容
if (head == tail)
doubleCapacity();
}
- addLast(E e)
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
//当tail==head时,扩容,其中,tail=tail+1,再对tail进行取余
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
- offerFirst(E e) 返回true/false
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
- offerLast(E e)
public boolean offerLast(E e) {
addLast(e);
return true;
}
- removeFirst()
public E removeFirst() {
E x = pollFirst();
if (x == null)
throw new NoSuchElementException();
return x;
}
- removeLast()
public E removeLast() {
E x = pollLast();
if (x == null)
throw new NoSuchElementException();
return x;
}
- pollFirst()
public E pollFirst() {
int h = head;
@SuppressWarnings("unchecked")
E result = (E) elements[h];
// Element is null if deque empty
if (result == null)
return null;
elements[h] = null; // Must null out slot
//取出头元素后,移动head指针
head = (h + 1) & (elements.length - 1);
return result;
}
- pollLast()
public E pollLast() {
//获得尾部元素的index,tail-1是因为tail指向下一个插入元素的位置
int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
if (result == null)
return null;
elements[t] = null;
//把tail向前移
tail = t;
return result;
}
- getFirst()
public E getFirst() {
@SuppressWarnings("unchecked")
E result = (E) elements[head];
if (result == null)
throw new NoSuchElementException();
return result;
}
- getLast()
public E getLast() {
@SuppressWarnings("unchecked")
E result = (E) elements[(tail - 1) & (elements.length - 1)];
if (result == null)
throw new NoSuchElementException();
return result;
}
- peekFirst()
public E peekFirst() {
// elements[head] is null if deque empty
return (E) elements[head];
}
- peekLast()
public E peekLast() {
return (E) elements[(tail - 1) & (elements.length - 1)];
}
- removeFirstOccurrence(Object o)
设e.removeFirstOccurrence(o),则移除第一个o.equals(e)的元素(从head到tail遍历deque)。如果deque中不包含这个元素,deque不变。如果包含,return true。
public boolean removeFirstOccurrence(Object o) {
if (o == null)
return false;
int mask = elements.length - 1;
int i = head;
Object x;
while ( (x = elements[i]) != null) {
if (o.equals(x)) {
delete(i);
return true;
}
i = (i + 1) & mask;
}
return false;
}
- add(E e); offer(E e); remove(); poll(); peek(); push(E e); pop()
其中,在头部进行操作的有:remove(); poll(); peek(); push(E e); pop();
在尾部进行操作的有:add(E e); offer(E e); - delete(int i)
移除指定位置的元素,并调整head和tail。将要删除位置后边的元素全部往前挪。
private boolean delete(int i) {
checkInvariants();
final Object[] elements = this.elements;
final int mask = elements.length - 1;
final int h = head;
final int t = tail;
final int front = (i - h) & mask;
final int back = (t - i) & mask;
// Invariant: head <= i < tail mod circularity
if (front >= ((t - h) & mask))
throw new ConcurrentModificationException();
// Optimize for least element motion
if (front < back) {
if (h <= i) {
System.arraycopy(elements, h, elements, h + 1, front);
} else { // Wrap around
System.arraycopy(elements, 0, elements, 1, i);
elements[0] = elements[mask];
System.arraycopy(elements, h, elements, h + 1, mask - h);
}
elements[h] = null;
head = (h + 1) & mask;
return false;
} else {
if (i < t) { // Copy the null tail as well
System.arraycopy(elements, i + 1, elements, i, back);
tail = t - 1;
} else { // Wrap around
System.arraycopy(elements, i + 1, elements, i, mask - i);
elements[mask] = elements[0];
System.arraycopy(elements, 1, elements, 0, t);
tail = (t - 1) & mask;
}
return true;
}
}