ArrayDeque和LinkedList同樣都實現了雙端隊列Deque接口,但它們內部的數據結構和使用方法卻不同。根據該類的源碼註釋翻譯可知:html
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable
因此ArrayDeque既能夠做爲隊列(包括雙端隊列xxxFirst,xxxLast),也能夠做爲棧(pop/push/peek)使用,並且它的效率也是很是高,下面就讓咱們一塊兒來讀一讀jdk1.8的源碼。java
//存儲隊列元素的數組 //power of two transient Object[] elements; //隊列頭部元素的索引 transient int head; //添加一個元素的索引 transient int tail; //最小的初始化容量(指定大小構造器使用) private static final int MIN_INITIAL_CAPACITY = 8;
//默認16個長度 public ArrayDeque() { elements = new Object[16]; } public ArrayDeque(int numElements) { allocateElements(numElements); } public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); }
ArrayDeque經過allocateElements()方法進行擴容。下面是allocateElements()源碼:算法
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]; }
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(8);
下面就從主要函數中來找找答案。數組
擴容是調用doubleCapacity() 方法,當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]; System.arraycopy(elements, p, a, 0, r); System.arraycopy(elements, 0, a, r, p); elements = a; head = 0; tail = n; }
經過位與計算找到下一個元素的位置。數據結構
public boolean add(E e) { addLast(e); return true; }
public void addLast(E e) { if (e == null) throw new NullPointerException(); elements[tail] = e; if ( (tail = (tail + 1) & (elements.length - 1)) == head) doubleCapacity(); }
add()函數實際上調用了addLast()函數,顧名思義這是將元素添加到隊列尾。前提是不能添加空元素。函數
8 & 7 = 0 (1000 & 111)
這就是爲了上面說的位與計算elements.length - 1 以此獲得下一個元素的位置tail。性能
和addLast相反,添加的元素都在隊列最前面線程
public void addFirst(E e) { if (e == null) throw new NullPointerException(); elements[head = (head - 1) & (elements.length - 1)] = e; if (head == tail) doubleCapacity(); }
-1 & (lements.length - 1)= lements.length - 1
因此第一次添加一個元素後head就變爲lements.length - 1翻譯
例如:
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(7); arrayDeque.addFirst(1); arrayDeque.addFirst(2); arrayDeque.addFirst(3);
執行時,ArrayDeque內部數組結構變化爲:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
3 | 2 | 1 |
第一次添加前head爲0,添加時計算:head = -1 & 7 , 計算head獲得7。
public E remove() { return removeFirst(); } public E removeFirst() { E x = pollFirst(); if (x == null) throw new NoSuchElementException(); return x; }
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 = (h + 1) & (elements.length - 1); return result; }
刪除元素其實是調用pollFirst()函數。
head = (h + 1) & (elements.length - 1); 位與計算head移動到下一個位置
public int size() { return (tail - head) & (elements.length - 1); }