ArrayDeque类是双端队列的实现类,继承自AbastractCollection其实现的接口Deque接口中定义了双端队列的主要的方法,不允许null元素存在,实现了Cloneable、Serializable 接口,支持复制、序列化的。
head指向第一个有效元素位置,tail指向尾部第一个可以插入元素的空闲位置。
无参构造函数,构造了一个大小为16的ArrayDeque。
public ArrayDeque(int numElements) { allocateElements(numElements); } 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]; }有参构造调用allocateElements(numElements),当用户要求分配的数组大小小于8时,分配8个空间。当用户要求分配的数组大小大于8时则分配大于用户需要内存的2的最小幂,最大分配2 ^ 30 大小的数组。
public ArrayDeque(Collection<? extends E> c) { allocateElements(c.size()); addAll(c); }传入容器的构造函数。
判断传入参数是否合法,不合法抛出空指针异常。head值先减1,然后将元素放到head位置, 如果head == tail 将数组大小扩大一倍。(head - 1) & (elements.length - 1) 使head的值在【0, elements.length - 1】范围之内,head一直围着数组转圈。head=tail时,数组中的元素已经满了,所以会将数组的扩大一倍。
如果传入元素为null,抛出空指针异常。将传入值赋给tail位置。
removeFirst方法调用了pollFirst方法,当容器为空时,removeFirst方法会抛出异常。下面给出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 = (h + 1) & (elements.length - 1); return result; }如果deque是空的,elment是null,调用elementAt方法。该方法其实就是在内部数组中根据下标,获取了一下元素。
removeLast方法调用了pollLast方法,删除并返回当前末端的元素。当容器为空时,抛出异常。
PriorityQueue是优先级队列,其底层通过堆实现,具体说是通过完全二叉树实现的小顶堆,排序采用自然排序或者通过提供的Comparator比较器去进行排序。不允许放入null元素。
PriorityQueue 使用数组 queue 来存储元素,默认初始容量是 11,最大容量是 Integer.MAX_VALUE - 8。comparator 若为 null,则按照元素的自然序来排列。modCount 用来提供 fail-fast 机制。
PriorityQueue 的构造函数有 7 个,可以分为两类,提供初始元素和不提供初始元素,有比较器和没有比较器。PriorityQueue中的对象要么有自己单独的比较器,要么对象所在类实现Comparable接口,需要保证当前对象可比较。
先看传入参数是否合法,然后判断是否需要扩容,需要扩容调用grow方法来进行扩容。如果队列为空,直接添加进队列,如果队列不为空,调用siftUp函数,代码如下:
private void siftUp(int k, E x) { if (comparator != null) siftUpUsingComparator(k, x); else siftUpComparable(k, x); }传入i为size,e为添加的值。如果传入比较器,按比较器比较进行添加,否则按自然顺序进行排序。
首先调用IndexOf()找这个元素在数组中的位置,保证元素不为空, 调用removeAt(i)函数删除指定位置元素。
private E removeAt(int i) { // assert i >= 0 && i < size; modCount++; int s = --size; if (s == i) // removed last element queue[i] = null; else { E moved = (E) queue[s]; queue[s] = null; siftDown(i, moved); if (queue[i] == moved) { siftUp(i, moved); if (queue[i] != moved) return moved; } } return null; }先size–,赋值给s,如果s等于i,删除的就是最后一个位置,直接置为空就删除掉了,反之要进行调整,将s位置置为空,然后用siftDown从上往下进行调整。如果所要删除的一个元素等于size-1的一个值,在进行从下往上siftUp。如果调整了以后不等于size-1的值,直接返回回去size-1的值。
private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); }该方法的作用是从k指定的位置开始,将x逐层向下与当前点的左右孩子中较小的那个交换,直到x小于或等于左右孩子中的任何一个为止。