一 ArrayDeque
- 数组存储数据,数组长度为2的次幂,初始空间为16
- head,tail保存数据起始的索引
- 循环存储数据
1.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
//扩容2倍容量
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
//分配数组空间
Object[] a = new Object[newCapacity];
//拷贝从head到数组尾的数据
System.arraycopy(elements, p, a, 0, r);
//拷贝从数组头到tail的数据
System.arraycopy(elements, 0, a, r, p);
elements = a;
//修改head,tail
head = 0;
tail = n;
}
1.2 数据拷贝
private T[] copyElements(T[] a) {
if (head < tail) {
//数据存储从head到tail
System.arraycopy(elements, head, a, 0, size());
} else if (head > tail) {
//数据存储从head到数组尾,从数组头到tail。分别拷贝到目标数组中
int headPortionLen = elements.length - head;
System.arraycopy(elements, head, a, 0, headPortionLen);
System.arraycopy(elements, 0, a, headPortionLen, tail);
}
return a;
}
1.3 增加
1.3.1 增加头
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
//head-1存储新增头部数据,& (elements.length - 1)使索引在数据长度范围内
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)//扩容
doubleCapacity();
}
1.3.2 增加尾
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
//存储尾部数据
elements[tail] = e;
//更新tail=tail+1,下次存储新增尾部数据的索引,& (elements.length - 1)使索引在数据长度范围内
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();//扩容
}
1.4 删除数据
1.4.1 删除头
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+1,并& (elements.length - 1),保证在数组长度范围内
head = (h + 1) & (elements.length - 1);
return result;
}
1.4.2 删除尾
public E pollLast() {
//tail-1,并& (elements.length - 1),保证在数组长度范围内
int t = (tail - 1) & (elements.length - 1);
@SuppressWarnings("unchecked")
E result = (E) elements[t];
if (result == null)
return null;
//删除引用
elements[t] = null;
tail = t;
return result;
}
二 PriorityQueue
- 优先级队列,使用一个最小堆结构实现
-
Object[] queue;
数组存储数据,queue[n]的子节点是queue[2n+1]和queue[2(n+1)],父节点值比子节点小
2.1 扩容
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// 小于64长度,则一倍扩容。否则扩容原容量的50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
2.2 新增
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)//空集合,直接赋值给索引0
queue[0] = e;
else//赋值给索引i=size,调整节点位置
siftUp(i, e);
return true;
}
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
private void siftUpComparable(int k, E x) {
Comparable super E> key = (Comparable super E>) x;
while (k > 0) {//循环比较直到根节点
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
//比父节点大,则已调整到正确的位置
break;
//比父节点小,则肯定比兄弟节点小,则和父节点更换位置
queue[k] = e;
k = parent;
}
//找到目标节点
queue[k] = key;
}
2.3 删除
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
//获取根节点
E result = (E) queue[0];
//把最后一个节点放到根节点
E x = (E) queue[s];
queue[s] = null;
if (s != 0)//调整节点位置
siftDown(0, x);
return result;
}
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
@SuppressWarnings("unchecked")
private void siftDownComparable(int k, E x) {
Comparable super E> key = (Comparable super E>)x;
int half = size >>> 1; // loop while a non-leaf
while (k < half) {//遍历向下调整,直到倒数第二层
//获取左右孩子索引
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child];
int right = child + 1;
//和左右孩子比较,父节点最小则调整完成
//否则和较小的孩子交换位置。
if (right < size &&
((Comparable super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
if (key.compareTo((E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = key;
}
三 Stack
- 栈存储,数据后进先出
- Stack继承自Vector,Vector中数据变更都使用synchronized加锁控制。
3.1 push添加
public E push(E item) {
addElement(item);
return item;
}
public synchronized void addElement(E obj) {
modCount++;
//总数加1
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
3.2 pop删除获取
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
public synchronized void removeElementAt(int index) {
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
//删除指定索引数据,拷贝索引后数据前移一位
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
//总数减1
elementCount--;
//释放数据引用
elementData[elementCount] = null; /* to let gc do its work */
}