ArrayDeque是可调整大小的双端队列实现。
用作栈的实现,性能优于Stack
用作队列的实现,性能优于LinkedList
基本结构
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable{
...
//内部是一个数组
transient Object[] elements;
//记录头部的index
transient int head;
//记录尾部的index, 记录的下一个将要保存的位置
transient int tail;
...
}
addFirst && offerFirst
//offerFirst内部是addFirst的实现
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
public void addFirst(E e) {
// 不可添加null的元素
if (e == null)
throw new NullPointerException();
//放在(head-1)的位置。
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
addFirst 在首部添加元素,head = (head - 1) & (elements.length - 1)等价于(head -1 ) % elements.length -1。初始时head = 0, 避免出现负数的索引,对elements.length -1 取模。
addLast & offerLast
//offerLast是addLast的实现
public boolean offerLast(E e) {
addLast(e);
return true;
}
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
//放在tail位置上
elements[tail] = e;
//tail = tail + 1
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}
addLast在尾部添加元素,元素放在element[tail]位置。避免越界,同样对数组的最大index取模。
添加元素的head, tail 变化图示:
tail 是下一个将要在尾部添加的元素的位置。head是上一个添加的位置
扩容 doubleCapacity
//扩容,扩大1倍
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");
//通过两次复制,将原来的数组复制到新数组的0...n的位置
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;
}
扩容图示:
当tail = head时进行扩容。
源码部分总有些让人觉得奇妙实现的地方。这个双端队列的实现和扩容思维真漂亮~
pollFirst && removeFirst
//队列为空时,removeFirst会抛出异常
public E removeFirst() {
E x = pollFirst();
if (x == null)
throw new NoSuchElementException();
return x;
}
//队列为空,不会抛出异常
public E pollFirst() {
int h = head;
@SuppressWarnings("unchecked")
// 取的是head元素
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;
}
peekFirst && element
//就是这么简单粗暴
@SuppressWarnings("unchecked")
public E peekFirst() {
// elements[head] is null if deque empty
return (E) elements[head];
}
//当队列为空,会抛出异常的哦~
public E element() {
return getFirst();
}
public E getFirst() {
@SuppressWarnings("unchecked")
E result = (E) elements[head];
if (result == null)
throw new NoSuchElementException();
return result;
}
ArrayDeque 总结
ArrayDeque 可调整大小的数组实现,可在队头和队尾操作
方法没有实现同步,线程不安全
不可添加null元素
为了将被动失眠变成主动熬夜,记录篇博文(╬▔︹▔)