一世相守铅华尽,人生至交莫如深。 (๑•̀ㅂ•́)و✧
ArrayDeque
基于数组
循环队列
实现了Deque这个接口来获得队列和栈的功能
不允许插入null
从源码看,空元素对于 ArrayDeque 没有实际影响,可能是基于
Deque的规范化建议
数组长度永远是2的指数幂
便于循环队列的实现,详见 循环队列
类图
graph BT
Iterable --> Collection
Queue --> Iterable
AbstractCollection -.-> Iterable
Serializable
Cloneable
Deque --> Queue
ArrayDeque --> AbstractCollection
ArrayDeque -.-> Serializable
ArrayDeque -.-> Cloneable
ArrayDeque -.-> Deque
内部变量
// 数组容器
transient Object[] elements;
// 头元素 角标
transient int head;
// 尾元素 角标
transient int tail;
// 数组最小长度
private static final int MIN_INITIAL_CAPACITY = 8;
构造函数
无参构造
public ArrayDeque() {
elements = new Object[16];
}
指定长度
public ArrayDeque(int numElements) {
allocateElements(numElements); // elements = new Object[calculateSize(numElements)];
}
private static int calculateSize(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY; // 8
if (numElements >= initialCapacity) {
// 计算大于numElements 的最小2指数幂
// e.g. numElements = 10, 那 initialCapacity = 16
// e.g. numElements = 17, 那 initialCapacity = 32
initialCapacity = numElements;
// e.p. 0..01...
initialCapacity |= (initialCapacity >>> 1);
// e.p. 0..011...
initialCapacity |= (initialCapacity >>> 2);
// e.p. 0..01111...
initialCapacity |= (initialCapacity >>> 4);
// e.p. 0..011111111...
initialCapacity |= (initialCapacity >>> 8);
// e.p. 0..01111111111111111...
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
// e.p. 0..1000000000000000...
if (initialCapacity < 0) // 越界处理
initialCapacity >>>= 1;
}
return initialCapacity;
}
扩容
何时扩容
if (head == tail)
doubleCapacity();
扩容操作
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p;
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 = a;
head = 0;
tail = n;
}
看的累,直接举栗
循环队列
先明白一个位运算技巧
a & (
elements.length- 1)
elements.length 就是数组长度,为 2的指数幂,二进制表示为 00100000...000
elements.length - 1 二进制表示为 00011111...111
elements.length > a >= 0 时
a & (
elements.length- 1) == a
a = -1 时,-1 的二进制: 11111...11111
a & (
elements.length- 1) ==elements.length- 1
a = elements.length 时
a & (
elements.length- 1) == 0
栈操作,移动 head
push 时
head = (head - 1) & (elements.length - 1)
这不就是向左移动吗
到 -1 时,就回到数组尾部 elements.length - 1
从这里能闻到循环的味道了
poll 时
head = (h + 1) & (elements.length - 1)
就是向右移动
到elements.length时,就回到数组头部 0
队列操作,移动 tail
和 head 相反
addLast时,向右移动
tail = (tail + 1) & (elements.length - 1)
removeLast时,向左移动
tail = (tail - 1) & (elements.length - 1)