表、棧和隊列是三種基本的數據結構,前面總結的ArrayList和LinkedList能夠做爲任意一種數據結構來使用,固然因爲實現方式的不一樣,操做的效率也會不一樣。 這篇要看一下java.util.ArrayDeque。從命名上看,它是一個由數組實現的雙端隊列。仍是先看一下它實現了哪些接口。java
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable {
在看看它的類註釋,做者是 大名鼎鼎的 Doug Lea, 大師級的人物,鄙人只能膜拜。上面balbala , biu biu biu ...... 的一大竄,大致是說,java.util.ArrayDeque是Deque接口的動態數組實現,容量會按需擴展,線程不安全。做爲棧使用比java.util.Stack快,做爲隊列使用比java.util.LinkedList快。大多數的操做消耗常數時間。主要特性就是這些。數組
在看源碼的時候,仍是老規矩,若是是你來作的話,你會如何來實現呢?首先,按照註釋的來,確定是要有個數組來保存數據啦,沒啥好說的。既然是雙端的隊列,必然有一個前,一個後的指針分別指向首尾。既然是一個數組,那麼優點就是在查找上,指針移動的速度就會很快,能夠快速的查找到元素的位置。總體的想法大概就是這樣。 那麼接下來,咱們來看看java.util.ArrayDeque的源碼吧。具體的源碼的實現。安全
/** * The array in which the elements of the deque are stored. * The capacity of the deque is the length of this array, which is * always a power of two. The array is never allowed to become * full, except transiently within an addX method where it is * resized (see doubleCapacity) immediately upon becoming full, * thus avoiding head and tail wrapping around to equal each * other. We also guarantee that all array cells not holding * deque elements are always null. */ private transient E[] elements; /** * The index of the element at the head of the deque (which is the * element that would be removed by remove() or pop()); or an * arbitrary number equal to tail if the deque is empty. */ private transient int head; /** * The index at which the next element would be added to the tail * of the deque (via addLast(E), add(E), or push(E)). */ private transient int tail; /** * The minimum capacity that we'll use for a newly created deque. * Must be a power of 2. */ private static final int MIN_INITIAL_CAPACITY = 8;
能夠看到,基本上是這樣。最後一個常量表示初始化的最小容量,註釋說明這個值必須是2的冪,這是爲何??, 源碼註釋是這樣說的,不知道爲啥, 先記住這個問題,繼續往下看。數據結構
/** * Constructs an empty array deque with an initial capacity * sufficient to hold 16 elements. */ public ArrayDeque() { elements = (E[]) new Object[16]; } /** * Constructs an empty array deque with an initial capacity * sufficient to hold the specified number of elements. * * @param numElements lower bound on initial capacity of the deque */ public ArrayDeque(int numElements) { allocateElements(numElements); } /** * Constructs a deque containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. (The first element returned by the collection's * iterator becomes the first element, or <i>front</i> of the * deque.) * * @param c the collection whose elements are to be placed into the deque * @throws NullPointerException if the specified collection is null */ public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); }
關注一些註釋,一共有3個構造方法。無參的構造方法會建立長度爲16的內部數組。接受一個集合的構造方法不用多說了,看一下接受「元素數量」的構造方法,裏面會調一個分配內部數組空間的方法。app
/** * Allocate empty array to hold the given number of elements. * * @param numElements the number of elements to hold */ 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 = (E[]) new Object[initialCapacity]; }
這個方法是根據給定numElements來進行內部數組空間的分配。這裏有一個前提,容量必須是2的冪,儘管如今還不知道爲何必須是2的冪,但先往下看。能夠看到若是numElements小於最小容量8的話,就會按最小容量來分配數組空間。若是大於等於8,會到一個條件語句中作一些操做,看下這些操做是幹嗎的。咱們知道若是一個2進制數是2的冪,那麼它的特色就是隻有一位是1。this
2^0 = 1 2^1 = 10 2^n = 10000...(n個0)
2^1 = 1 + 1 2^3 = 111 + 1 2^n = 111...(n個1) + 1