java集合之ArrayDeque(3)
ArrayDeque介绍
原文地址:arrayDeque
ArrayDeque和LinkedList是Deque(double ended queue)的两个通用实现,官方更推荐使用AarryDeque用作栈和队列。
从名字可以看出ArrayDeque底层通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,该数组还必须是循环的,即循环数组(circular array),也就是说数组的任何一点都可能被看作起点或者终点。ArrayDeque是非线程安全的(not thread-safe),当多个线程同时使用的时候,需要程序员手动同步;另外,该容器不允许放入null元素。

从图中可以看出head指向第一个有效元素,tail指向最后一个有效元素,所以head不一定等于0,tail也不一定大于head。
方法剖析
addFirst(E e) :在对首插入一个元素,即head前添加一个元素

public void addFirst(E e) { if (e == null)//不允许放入null throw new NullPointerException(); elements[head = (head - 1) & (elements.length - 1)] = e;//2.下标是否越界 if (head == tail)//1.空间是否够用 doubleCapacity();//扩容 }
注:有序在判断head-1是否越界时,可能存在head-1为负数的情况,所以(head-1) & (elements.length-1)既可以判断数组是否越界,也可以解决为负数的情况因为elements.length必需是2的指数倍,elements - 1就是二进制低位全1,跟head - 1相与之后就起到了取模的作用,如果head - 1为负数(其实只可能是-1),则相当于对其取相对于elements.length的补码。
如果空间不足,会调用扩容函数扩容

//doubleCapacity() private void doubleCapacity() { assert head == tail; int p = head; int n = elements.length; int r = n - p; // head右边元素的个数 int newCapacity = n << 1;//原空间的2倍 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 = (E[])a; head = 0; tail = n; }
注:扩容后满足head == 0 ,head < tail (扩容后是原来的2倍)
addLast(E e):向tail后一个位置插入元素,同样容量不足,扩容。
pollFirst():作用是删除并返回Deque首端元素,也即是head位置处的元素。如果容器不空,只需要直接返回elements[head]即可,当然还需要处理下标的问题。由于ArrayDeque中不允许放入null,当elements[head] == null时,意味着容器为空。
public E pollFirst() { E result = elements[head]; if (result == null)//null值意味着deque为空 return null; elements[h] = null;//let GC work head = (head + 1) & (elements.length - 1);//下标越界处理 return result; }
pollLast:删除并返回Deque尾端元素,也即是tail位置前面的那个元素.
peekFirst():返回但不删除Deque首端元素,也即是head位置处的元素,直接返回elements[head]即可。
peekLast():返回但不删除Deque尾端元素,也即是tail位置前面的那个元素。

浙公网安备 33010602011771号