JDK容器學習之Queue: PriorityQueue

優先級隊列 PriorityQueue

單端隊列,隊列中的元素有優先級的順序java

title

1. 底層數據結構

// 存儲隊列元素的數組
transient Object[] queue;

// 隊列中實際元素的個數
private int size = 0;

// 比較器,用於定義隊列中元素的優先級
private final Comparator<? super E> comparator;

從成員變量的定義能夠看出,底層數據存儲依然是數組,然而同javadoc中解釋,實際的存儲結構倒是二叉樹(大頂堆,小頂堆);數組

至於隊列中成員的優先級使用comparator或者成員變量自己的比較來肯定數據結構

下面經過添加和刪除元素來肯定數據結構code

struct

2. 常見接口實現方式

刪除元素

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);
}

private void siftDownUsingComparator(int k, E x) {
    int half = size >>> 1;
    while (k < half) {
        int child = (k << 1) + 1;
        Object c = queue[child];
        int right = child + 1;
        if (right < size &&
            comparator.compare((E) c, (E) queue[right]) > 0)
            c = queue[child = right];
        if (comparator.compare(x, (E) c) <= 0)
            break;
        queue[k] = c;
        k = child;
    }
    queue[k] = x;
}

shifDownUsingComparator 實現的就是維持小頂堆二叉樹的邏輯,後面以添加爲例,給一個圖解接口

添加元素

肯定存儲結構爲小頂堆以後,再看添加元素隊列

public boolean offer(E e) {
    if (e == null) // 非null
        throw new NullPointerException();
    modCount++;
    int i = size;
    if (i >= queue.length) // 動態擴容
        grow(i + 1);
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);
    return true;
}


// 擴容邏輯,擴容爲新size的兩倍,或者新增原來容量的一半
private void grow(int minCapacity) {
    int oldCapacity = queue.length;
    // Double size if small; else grow by 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);
}

// 二叉樹重排
private void siftUp(int k, E x) {
    if (comparator != null)
        siftUpUsingComparator(k, x);
    else
        siftUpComparable(k, x);
}

private void siftUpUsingComparator(int k, E x) {
    while (k > 0) {
        int parent = (k - 1) >>> 1;
        Object e = queue[parent];
        if (comparator.compare(x, (E) e) >= 0)
            break;
        queue[k] = e;
        k = parent;
    }
    queue[k] = x;
}

add

3. 使用姿式&小結

  1. PriorityQueue 存儲結構爲二叉樹,小頂堆
  2. 默認數組長度爲11,超過容量會觸發擴容邏輯,擴容爲隊列個數的兩倍或新增源容量的一半
  3. 隊列元素不能爲null
  4. 新增or刪除元素,均可能引發二叉樹的重排

掃描關注,java分享

相關文章
相關標籤/搜索