1、並非按FIFO進出
傳統的queue 是按先進先出的順序執行。而PriorityQueue是按優先級來絕對的
優先級低的先出queue
2、如何排序
PriorityQueue既然有優先級排序 那么如何排序的。
a. 放入隊列的元素實現了Comparable接口 按其自然順序排序 從小到大。
b. 初始化隊列時指明Comparator外部比較器。
PriorityQueue<String> queue1 = new PriorityQueue<>(); PriorityQueue<String> queue2 = new PriorityQueue<>(10); PriorityQueue<String> queue3 = new PriorityQueue<>((a,b)->a.compareTo(b));
3、內部結構
內部使用數組存放元素:
transient Object[] queue;
數組默認容量11 (初始化時可以指定)
動態擴容機制
容量<64 擴容為2*n+2,否則跟ArrayList一樣擴大為1.5n
(64是一個權衡的不大不小的值)
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); }
小根堆實現
小根堆:是一種完全二叉樹 且滿足父節點不大於任意一個左右子節點。(注意左右節點是沒有順序的)
所以小根堆的頂點必然是最小的 (如何要實現從大到小排序,指定的Comparator中取相反順序即可)
而完全二叉樹(所有節點滿足從左到右排列 不會垮節點)是可以用數組表示的。
PriorityQueue就是使用數組來實現的小根堆: 滿足每次取的數據都是最小的,但不滿足整體都是有序的。
任意一個節點(數組中索引為n) 都可以知道其左右子節點和父節點在數組中的索引值:
父節點 : (n-1)/2
左子節點: 2n+1
右子節點:2n+2
關於節點的增刪
增:在完全二叉樹中依次創建一個新節點,再把新節點跟父節點依次比較,使其滿足最小堆要求
刪:刪除的節點 用二叉樹的最后一個節點先填充,再進行調整。
總是都是拿最有的節點處理,因為要滿足完全二叉樹。
具體細節網上例子很多 不再詳解。
4、非線程安全
PriorityQueue的線程安全版本:PriorityBlockingQueue,使用ReentrantLock加鎖保護