一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|

服務器之家 - 編程語言 - JAVA教程 - JDK源碼之PriorityQueue解析

JDK源碼之PriorityQueue解析

2020-09-18 14:19_fred JAVA教程

這篇文章主要為大家詳細介紹了JDK源碼之PriorityQueue,具有一定的參考價值,感興趣的小伙伴們可以參考一下

一.優先隊列的應用

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

二.優先隊列的實現原理

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

  1.任何結點的值都小于或等于其子節點的值。
  2.所有結點從上到下,從左到右填入,即一棵完全二叉樹。

基于這兩條規律,二叉堆在實現中往往會使用一個數組,下面我們研究一下JDK中二叉堆(優先隊列)的實現。

三.優先隊列在JDK中的實現方式

研究源碼最好的方式是debug,看每一步變量的變化,我們可以簡單寫一個Demo,debug進源碼一探究竟:

JDK源碼之PriorityQueue解析

這里我們簡單地創建一個優先隊列,向其中添加三個元素,我們可以在代碼第一行打一個斷點,如果您使用Eclipse編輯器的話,接下來可以按F5進入源碼中:

JDK源碼之PriorityQueue解析

代碼運行到這里,PriorityQueue調用自己的一個重載構造器,第一個參數是數組默認大小,第二個是元素比較的Comparator,我們這里的Demo比較簡單,您在使用優先隊列時可以選擇實現自己的Comparator。

?
1
2
3
4
5
6
7
8
9
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;
 }

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public boolean offer(E e) {
   if (e == null)
     throw new NullPointerException();
   //記錄了隊列被修改的次數
   modCount++;
   int i = size;
   if (i >= queue.length)
     //擴容
     grow(i + 1);
   //增加元素個數
   size = i + 1;
   if (i == 0)
     //第一次添加元素,直接放到第0個位置即可
     queue[0] = e;
   else
     //需要將元素放到最后,再做上濾操作
     siftUp(i, e);
   return true;
 }

我們逐行來解釋一下,首先offer方法判斷參數是否為空,不為空則對變量modCount自增,modCount記錄了隊列被修改的次數,接下來,判斷數組是否會越界,如果越界則通過grow進行擴容,接下來添加元素,如果當前元素為0個則直接將元素放到數組第一個位置,否則做一個siftUp的操作。

?
1
2
3
4
5
6
7
8
9
10
11
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);

上面的代碼對隊列擴容,源碼中注釋也很清晰,首先判斷當前的數組大小是否足夠小(<64),如果足夠小則將大小擴充為2倍,否則將原大小加上50%。需要注意的是,這里最后做了一個大小是否溢出的判斷。

?
1
2
3
4
5
6
7
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
      throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
      Integer.MAX_VALUE :
      MAX_ARRAY_SIZE;
  }

如果需要擴容的大小已經<0了,顯然已經溢出了,在這里拋出了OutOfMemory的異常。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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;
  }

為了保證優先隊列的性質1,在插入每個元素時都需要與該節點父親進行比較,找到其正確位置,有些數據結構書中,這個操作被稱為上濾(percolate up)。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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做一些調整,保證隊列的性質,這個操作被稱為下濾(percolate down)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void siftDownUsingComparator(int k, E x) {
 
 
   int half = size >>> 1;
   //這里k必須有孩子,故葉節點需要比較
   while (k < half) {
     //以下幾行代碼到較小的那個兒子,用變量c表示
     int child = (k << 1) + 1;
     //這里假設左兒子比較小
     Object c = queue[child];
     int right = child + 1;
     //左右兒子比較,如果右兒子小則將c賦值為右兒子
     if (right < size &&
       comparator.compare((E) c, (E) queue[right]) > 0)
       c = queue[child = right];
     //如果x比小兒子還小,說明k就是正確位置
     if (comparator.compare(x, (E) c) <= 0)
       break;
     queue[k] = c;
     k = child;
   }
   queue[k] = x;
 }

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/showing/p/6759341.html

延伸 · 閱讀

精彩推薦
  • JAVA教程java中lambda表達式簡單用例

    java中lambda表達式簡單用例

    讓我們從最簡單的例子開始,來學習如何對一個string列表進行排序。我們首先使用Java 8之前的方法來實現 ...

    robin4722020-06-15
  • JAVA教程深入理解Java的接口與抽象類

    深入理解Java的接口與抽象類

    本文主要介紹java 的接口和抽象類,對接口和抽象類進行介紹對比,深入理解,有需要的小伙伴可以參考下 ...

    java技術網3142020-05-29
  • JAVA教程Spring Boot中Redis數據庫的使用實例

    Spring Boot中Redis數據庫的使用實例

    Spring Boot中除了對常用的關系型數據庫提供了優秀的自動化支持之外,對于很多NoSQL數據庫一樣提供了自動化配置的支持。本篇文章主要介紹了Spring Boot中...

    心碎落地的聲音1932020-09-06
  • JAVA教程Datagram Scoket雙向通信

    Datagram Scoket雙向通信

    這篇文章主要介紹了Datagram Scoket雙向通信,需要的朋友可以參考下 ...

    Java教程網2412019-11-20
  • JAVA教程java正則表達式獲取url的host示例

    java正則表達式獲取url的host示例

    使用httpclient抓取頁面信息時需要填寫HOST,使用此正則提取抓取URL的HOST內容 ...

    java教程網4312019-11-08
  • JAVA教程Spring-data-redis操作redis知識總結

    Spring-data-redis操作redis知識總結

    這篇文章主要介紹了Spring-data-redis操作redis知識總結,spring-data-redis是spring-data模塊的一部分,專門用來支持在spring管理項目對redis的操作。...

    醉眼識朦朧5012020-09-11
  • JAVA教程Java基礎之如何學好Java

    Java基礎之如何學好Java

    這篇文章已經是有數年“網齡”的老文,不過在今天看來仍然經典。如何學習java?本篇文章可以說也是面對編程初學者的一篇指導文章,其中對于如何學習...

    hebedich4962019-12-03
  • JAVA教程Maven 生成打包可執行jar包的方法步驟

    Maven 生成打包可執行jar包的方法步驟

    這篇文章主要介紹了Maven 生成打包可執行jar包的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    荒野雄兵4552020-09-05
主站蜘蛛池模板: 操黄| 幻女free性zozo交体内谢 | 精品一区二区三区高清免费观看 | 国产福利专区精品视频 | 4hc44四虎www在线影院男同 | 亚洲精品第二页 | 欧美日韩亚洲另类人人澡 | 99久久精品99999久久 | 男女18一级大黄毛片免 | 日日网| 久久午夜夜伦痒痒想咳嗽P 久久无码AV亚洲精品色午夜麻豆 | 91高清免费国产自产 | 国产成人 免费观看 | 亚洲国产高清视频 | 性欧美video| 欧美怡红院视频一区二区三区 | 久久国产精品无码视欧美 | 高h辣h双处全是肉军婚 | 高h辣h双处全是肉军婚 | 国产精品精品 | 免费观看在线aa | 午夜福利院电影 | 国产精品四虎在线观看免费 | 久久大胆视频 | 免费观看全集 | 国产短视频精品一区二区三区 | 国产绳艺在线播放 | 欧美一级欧美三级在线 | 国产一久久香蕉国产线看观看 | 艹b小说| 羞羞在线观看 | 美女靠逼免费网站 | 亚洲美女爱爱 | 国内精品久久久久久久 | 精品综合久久久久久97超人 | 91精品天美精东蜜桃传媒免费 | 国产精品久久久久久久久久久久 | 日本wwxx| 亚洲视频在线观看免费 | 蜜桃成熟时1997在线看免费看 | 学校女性奴sm训练调教 |