ArrayDeque简介说明
下文笔者讲述ArrayDeque简介说明
ArrayDeque简介
ArrayDeque是Deque接口的一种实现 依赖于可变数组来实现的 ArrayDeque没有容量限制,可根据需求自动进行扩容 ArrayDeque可作为栈来使用,效率要高于Stack ArrayDeque可以作为队列来使用,效率相较于基于双向链表的Linkedlist也要更好一些
ArrayDeque的成员变量
//数组存储元素 transient Object[] elements; //头部元素索引 transient int head; //尾部元素索引 transient int tail; //最小容量 private static final int MIN_INITIAL_CAPACITY = 8;
ArrayDeque底层使用数组存储元素 同时还使用head和tail来表示索引 但注意tail不是尾部元素的索引 而是尾部元素的下一位 即下一个将要被加入的元素的索引
ArrayDeque如何初始化
public ArrayDeque() { elements = new Object[16]; } public ArrayDeque(int numElements) { allocateElements(numElements); } public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); } 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的初始化容量必须是2^n 你传的初始化容量如果是10 那么实际申请的数组容量是16 如果申请的容量是33,那么实际的容量是62 如果申请的容量是62,那么实际申请的容量是128。 我们可以从allocateElements方法中看出以上的运行原理
ArrayDeque中add方法
public void addFirst(E e) { if (e == null) throw new NullPointerException(); elements[head = (head - 1) & (elements.length - 1)] = e; if (head == tail) doubleCapacity(); } public void addLast(E e) { if (e == null) throw new NullPointerException(); //tail中保存的是即将加入末尾的元素的索引 elements[tail] = e; //tail向后移动一位 if ( (tail = (tail + 1) & (elements.length - 1)) == head) //tail和head相遇,空间用尽,需要扩容 doubleCapacity(); } 注意事项: tail的计算公式(tail = (tail + 1) & (elements.length - 1)) 当tail到达容量最后一个的时候,tail就为等于0,否则tail的值tail+1
ArrayDeque扩容机制
private void doubleCapacity() { assert head == tail; //扩容时头部索引和尾部索引肯定相等 int p = head; int n = elements.length; //头部索引到数组末端(length-1处)共有多少元素 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; }
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。