優先級隊列~~~~~~~~~

隊列與棧兩種數據結構是老生常談的問題了,其中隊列是先進先出(FIFO),棧是先進後出(FILO),明白這兩個特性,就很簡易理解了。但是有一種特殊的隊列也是我們常用的數據結構——優先級隊列。

優先隊列的作用是能保證每次取出的元素都是隊列中權值最小(大)的,Java中PriorityQueue實現了Queue接口,不允許放入null元素;其通過堆實現,具體說是通過完全二叉樹(complete binary tree)實現的小頂堆(任意一個非葉子節點的權值,都不大於其左右子節點的權值),也就意味着可以通過數組來作爲PriorityQueue的底層實現。如下圖所式:

優先級隊列

下面着重兩個方法說明,添加元素與移除元素。

添加元素時,通過siftUp(int k, E x);方法維持特性。

 1public boolean offer(E e) {
 2    if (e == null)//不允許放入null元素
 3        throw new NullPointerException();
 4    modCount++;
 5    int i = size;
 6    if (i >= queue.length)
 7        grow(i + 1);//自動擴容
 8    size = i + 1;
 9    if (i == 0)//隊列原來爲空,這是插入的第一個元素
10        queue[0] = e;
11    else
12        siftUp(i, e);//調整
13    return true;
14}
15
16private void siftUp(int k, E x) {
17    while (k > 0) {
18        int parent = (k - 1) >>> 1;//parentNo = (nodeNo-1)/2
19        Object e = queue[parent];
20        if (comparator.compare(x, (E) e) >= 0)//調用比較器的比較方法
21            break;
22        queue[k] = e;
23        k = parent;
24    }
25    queue[k] = x;
26}

k爲數組最大下標值。 看下圖所示:

優先級隊列

 1//代碼運行過程
 2-> x = 4;
 3-> k = 10;
 4-> parent = (k-1)/2 = 4.5 === 4;
 5-> e = 9;
 6-> compare(4, 9) = -1 < 0;
 7-> queue[10] = 9;
 8-> k = 4;
 9-> parent = (k-1)/2 = 1.5 === 1;
10-> e = 5;
11-> compare(4,5) = -1 < 0;
12-> queue[4] = 5;
13-> k=1;
14-> parent = (k - 1) / 2 = 0 / 2 === 0;
15-> e = 3;
16-> compare(4, 3) = 1 > 0;
17//跳出while循環
18-> queue[1] = x => queue[1] = 4;

至此,添加元素的過程結束。
再看一下poll過程,poll過程是通過siftDown(int k , E e);來維持特性。

 1public E poll() {
 2    if (size == 0)
 3        return null;
 4    int s = --size;
 5    modCount++;
 6    E result = (E) queue[0];//0下標處的那個元素就是最小的那個
 7    E x = (E) queue[s];
 8    queue[s] = null;
 9    if (s != 0)
10        siftDown(0, x);//調整
11    return result;
12}
13
14private void siftDown(int k, E x) {
15    int half = size >>> 1;
16    while (k < half) {
17        //首先找到左右孩子中較小的那個,記錄到c裏,並用child記錄其下標
18        int child = (k << 1) + 1;//leftNo = parentNo*2+1
19        Object c = queue[child];
20        int right = child + 1;
21        if (right < size &&
22            comparator.compare((E) c, (E) queue[right]) > 0)
23            c = queue[child = right];
24        if (comparator.compare(x, (E) c) <= 0)
25            break;
26        queue[k] = c;//然後用c取代原來的值
27        k = child;
28    }
29    queue[k] = x;
30}

k的初始值爲0,x爲最後一個元素。
過程如圖所示:

優先級隊列

 1//代碼運行過程
 2-> k = 0;
 3-> x = 9;
 4-> half = 10 / 2 = 5;
 5-> child = 0 + 1 = 1;
 6-> c = 4;
 7-> right = child + 1 = 2;
 8// 2<10 && compare(4, 10)<0第一個判斷不成立
 9-> compare(9, 4) > 0;
10-> queue[0] = 4;
11-> k = 1;
12-> child = 2 * 1 + 1 = 3;
13-> c = 7;
14-> right = 4;
15-> 4 < 10 && compare(7, 5)>0
16-> child = 4;
17-> c = 5;
18-> compare(9, 5)>0
19-> queue[1] = 5;
20-> k = 4;
21-> child = 2 * 4 + 1 = 9;
22-> c = 12;
23-> right = 10;
24// 10<10第一個判斷不成立
25-> compare(9, 12)<0;
26//跳出while循環
27-> queue[4] = 9

至此,poll操作過程結束。高質量編程視頻shangyepingtai.xin

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章