- PriorityQueue,我用過的場景是用來構建大小堆。
- PriorityQueue的排序是在創建時就制定的Comparable或Comparator。
- PriorityQueue不允許添加null元素。
- 如果隊列中插入Comparable或Comparator無法比較的元素時,會拋出ClassCastException異常。
- 隊列頭是隊列的最後一個元素。如果最後一個值有多個元素的話,隊列頭是任意一個元素。
- 隊列可通過poll,remove,peek,element方法獲取隊列頭,即隊列的最後一個元素。
- PriorityQueue的長度沒有限制,內部變量capacity用於管理隊列長度,當添加元素時,容量會自動增加。
- PriorityQueue不是同步的,如果一個線程在修改PriorityQueue的話,其他線程無法獲取該PriorityQueue。在這種情況下,考慮線程安全的類:java.util.concurrent.PriorityBlockingQueue
- 時間複雜度是O(log(n))的方法:offer,poll,remove(),add
- 時間複雜度是O(n)的方法:remove(Object),contains(Object)
- 時間複雜度是O(1)的方法:peek,element,size
PriorityQueue實現了java.io.Serializable接口,指定了serialVersionUID
PriorityQueue聲明瞭默認的容量DEFAULT_INITIAL_CAPACITY = 11;
transient關鍵字無法被序列化
final關鍵字:
- 修飾類:該類不可以被繼承
- 修飾方法:該方法不可以被重寫
- 修飾變量:該變量不可以被修改
-
Comparator用private final 修飾,使得Comparator只可以在初始化時被指定,且不可以在其他時候修改。
private final Comparator<? super E> comparator; -
在初始化優先隊列的容量時,最小是1,否則拋出IllegalArgumentException。
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
-
PriorityQueue可通過Collection的實現類構建,前提是實現類是
SortedSet的子類或者是PriorityQueue的實例,也就是本身就有comparator的實例,否則無法創建。 -
創建實例時,將Collection的實現類使用toArray()轉換爲數組,並遍歷,判斷有沒有null元素。
-
優先隊列的最大size如下:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
以爲部分虛擬機要在數組頭存儲東西,所以爲了避免爆內存-8. -
PriorityQueue實現的基礎是平衡二叉堆,存儲在數組中,元素queue[n] 的左孩子和右孩子分別爲queue[2n+1] 、queue[2(n+1)]
-
因爲上述存儲方式,PriorityQueue頭就是0位元素,所以返回數組的第0位。
public E peek() { return (size == 0) ? null : (E) queue[0];}
/>>>表示無符號右移,也叫邏輯右移,即若該數爲正,則高位補0,而若該數爲負數,則右移後高位同樣補0
- 添加元素時,用到offer函數,offer函數調用siftUpUsingComparator函數,siftUpUsingComparator函數的k是添加該元素之後的隊列的長度,x是該元素,如果想在第k位存儲元素,則該元素的父結點爲m位的元素,2*m+1=k, m=(k- 1)/2 ,如果該元素大於等於父元素,則直接保存,否則把父元素寫在當前的位置上,再找當前元素的父元素,因此offer的時間複雜度是O(log(n))。
如果調用compare方法大於0,就把前一個數和後一個數交換,也就是把大的數放後面了
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;
}
- poll方法直接把最後一位賦爲空,並傳入最後一位元素到siftDown函數中。
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;
}
- siftDown方法調用siftDownComparable函數,對size除2,size是原來的size0-1之後的結果,half=(size0-1)/2,即half所在的元素是第size0位的父結點。k是0,如果k小於half,則證明還沒有把父結點填充上,需要獲取k的左孩子c,如果左孩子大於右孩子,則把child指向右孩子,並把有孩子賦值給c用c去替換父節點,直到替換到跟節點。
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;
}
- contains要遍歷一邊數組,所以是O(n)