JDK原始碼之PriorityQueue原始碼剖析

2021-09-12 10:58:06 字數 1871 閱讀 4646

優先佇列在程式開發中屢見不鮮,比如作業系統在進行程序排程時一種可行的演算法是使用優先佇列,當乙個新的程序被fork()出來後,首先將它放到佇列的最後,而作業系統內部的scheduler負責不斷地從這個優先佇列中取出優先順序較高的程序執行;爬蟲系統在執行時往往也需要從乙個優先順序佇列中迴圈取出高優先順序任務並進行抓取。可以想見,如果類似這樣的任務不適用優先順序進行劃分的話,系統必會出現故障,例如作業系統中低優先順序程序持續占用資源而高優先順序程序始終在佇列中等待。此外,優先佇列在貪婪演算法中也有一些應用。

優先佇列的實現方式是使用二叉堆的結構,需要滿足以下兩條性質(heap property),這裡以小頂堆為例講解:

1.任何結點的值都小於或等於其子節點的值。

2.所有結點從上到下,從左到右填入,即一棵完全二叉樹。

基於這兩條規律,二叉堆在實現中往往會使用乙個陣列,下面我們研究一下jdk中二叉堆(優先佇列)的實現。

研究原始碼最好的方式是debug,看每一步變數的變化,我們可以簡單寫乙個demo,debug進原始碼一**竟:

**執行到這裡,priorityqueue呼叫自己的乙個過載構造器,第乙個引數是陣列預設大小,第二個是元素比較的comparator,我們這裡的demo比較簡單,

您在使用優先佇列時可以選擇實現自己的comparator。

public priorityqueue(int initialcapacity,

comparator super e> comparator)

接下來我們研究一下新增元素時的offer操作:

public boolean offer(e e)
我們逐行來解釋一下,首先offer方法判斷引數是否為空,不為空則對變數modcount自增,

modcount記錄了佇列被修改的次數,接下來,判斷陣列是否會越界,如果越界則通過grow進行擴容,

接下來新增元素,如果當前元素為0個則直接將元素放到陣列第乙個位置,否則做乙個siftup的操作。

private void grow(int mincapacity)
如果需要擴容的大小已經<0了,顯然已經溢位了,在這裡丟擲了outofmemory的異常。

private void siftupusingcomparator(int k, e x) 

queue[k] = x;

}

為了保證優先佇列的性質1(每個節點的子節點都要大於或者等於自己),在插入每個元素時都需要與該節點父親進行比較,找到其正確位置,

有些資料結構書中,這個操作被稱為上濾(percolate up)。

入隊操作已經說完了,接下來是出隊操作,即poll()操作:

public e poll()
這個方法首先將陣列第乙個元素作為結果,(因為如果是小頂堆的話堆頂始終是最小元素),並將佇列的最後乙個元素放到第乙個位置,最後用

siftdown做一些調整,保證佇列的性質,這個操作被稱為下濾(percolate down)。

private void siftdownusingcomparator(int k, e x) 

queue[k] = x;

}

如上圖,下濾過程中k不斷與其兒子進行比較,如果滿足優先佇列的順序性,則break出迴圈。

原始碼解析 JDK原始碼之LinkedHashMap

linkedhashmap原始碼,基於 jdk1.6.43 他繼承了hashmap,並且實現了插入和訪問的有序功能 public class linkedhashmapextends hashmapimplements map 其也有乙個entry內部類,繼承了 hashmap 的entry 內部類...

JDK原始碼之Map

1.hashmap hashmap初始化的方式有四種。建立乙個entry陣列,預設初始長度為16,當大於0.75的時候,擴充套件為當前的2倍。有4中初始化map的方式。mapmap new hashmap mapmap2 new hashmap 17 mapmap3 new hashmap 15,2...

JDK原始碼之HashMap

部分重要屬性 存放key,value的陣列 transient node table 存放entry的set transient set entryset hashmap的大小 預設16 transient int size 修改次數 transient int modcount 擴擴容閾值capa...