Queue和Stack

一 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 key = (Comparable) 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 key = (Comparable)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) 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 */
}

你可能感兴趣的:(Queue和Stack)