PriorityQueue是基於無界優先級隊列和優先級堆構建的重要Java API之一。本文通過適當的代碼示例深入了解了有關此API及其用法的一些復雜信息。另在上篇文章中我們簡單地談了下Java編譯器API簡介,你可以先閱讀以方便更好地閱讀這篇文章。感謝優銳課老師對我寫下這兩篇文章時給予的幫助。
總覽
PriorityQueue類是java.util包的一部分,是Java中基於優先級的隊列的通用實現。隊列基本上是一種數據結構,它定義了針對商店中商品的插入和檢索過程的特定規范。這個想法與排隊等候說票的許多人非常相似。排隊的第一個人有第一個獲得彩票的機會,最后一個人有一個結局的機會。人們被添加到隊列的末尾或末尾。在隊列中添加項目在技術上稱為入隊過程,從隊列中刪除的項目是從該行的第一行開始。這稱為出隊。想法是以先進先出的方式對元素進行排序。
現在,這是最簡單的體系結構,並且緊密定義了隊列的實際含義以及如何在計算機中模擬隊列。存儲通常由一個簡單的數組表示,其中存儲和檢索過程具有此定義的規范。優先級隊列在此之上強加一些特殊規范。我們將在后面看到更多內容。
隊列的Java實現
Java API在java.util包中具有通用接口名稱Queue <E>。這是Java Collection Framework API的一部分,旨在在處理之前保存元素。作為集合的一部分,它具有所有基本的集合操作。特定於其標識的操作涉及存儲在其中的元素的插入,提取和檢查。這些操作中的每一個都有兩種不同的形式,例如一種在操作失敗時引發異常,而另一種則根據操作返回一個特殊值,例如null或false。請注意,與典型隊列不同,Java Queue的具體實現不必一定以FIFO方式對元素進行排序。對於基於優先級的隊列尤其如此,其中元素的排序是根據提供的比較器或自然排序完成的。但是無論順序如何,remove()或poll()方法將始終檢索隊列開頭的元素。這兩種不太可能的方法之間的特定區別似乎是一種相似的方法,即在失敗時引發異常(NoSuchElementException),而后者則返回特殊值(null)。
| 方法 |
引發異常 |
描述 |
|
||
| E remove() |
NoSuchElementException |
從隊列的開頭檢索一個元素。 |
|
||
| void add(E) |
IllegalStateException |
在隊列末尾插入一個元素。成功返回true,如果空間不可用則拋出異常。 |
|
||
| E element() |
NoSuchElementException |
檢索元素而不將其從隊列的開頭移除。 |
|
||
|
|
|
|
|||
| 方法 |
返回特殊值 |
說明 |
|||
| boolean offer(E) |
true or false |
將元素插入隊列。成功返回true,如果由於空間不足而無法插入,則返回false。 |
|||
| E poll() |
null |
從隊列的開頭移除元素;如果隊列為空,則返回null。 |
|||
| E peek() |
null |
檢索但不從隊列的開頭刪除元素。如果隊列為空,則返回null。 |
|||
請注意,Queue <E>接口不適用於並發編程,因為它沒有定義阻塞隊列方法,在這種方法中,入隊和出隊過程等待元素出現在隊列中或大小可用。有一個名為BlockingQueue <E>的特定接口,該接口擴展了Queue <E>接口並解決了這些問題。
有一個稱為AbstractQueue <E>的抽象類,該類提供某些隊列操作的部分實現。 PriorityQueue <E>類是此抽象類的直接擴展。
優先隊列
優先級隊列的Java實現是一種特殊的隊列,其中元素的排序由其自然排序原則確定,也可以根據創建期間提供的Comparator進行定制。我們在構造過程中調用的構造函數決定要與優先級隊列一起使用的排序原則。與不允許使用null元素的Queue <E>不同,但是某些實現(例如LinkedList)也不禁止插入null元素。但是,PriorityQueue <E>根本不允許空元素。如果優先級隊列是根據自然順序構造的,則任何不可比較的元素插入都將引發ClassCastException。
它被聲明為無限制的並且基於優先級堆。盡管隊列的大小被稱為無限制,但內部具有確定陣列大小的能力。插入元素時,此大小會自動增長。但是,沒有詳細說明增大尺寸的原理。
有七種類型的重載構造函數,通過它們我們可以設置參數來指定隊列的初始容量,提供Comparator來指定元素的自定義順序,或者使用無參數構造函數將所有內容接受為默認值。
- PriorityQueue()
- PriorityQueue(int initialCapacity)
- PriorityQueue(int initialCapacity, Comparator<? Super E> comparator)
- PriorityQueue(Commection<? extends E> c)
- PriorityQueue(Comparator<? Super E> comparator)
- PriorityQueue(PriorityQueue<? extends E> c)
- PriorityQueue(SortedSet<? extends E> c)
與Queue <E>相似,PriorityQueue <E>也不同步,因此在並發編程中應謹慎使用。但是,有一個同步的替代方法,稱為PriorityBlockingQueue <E>。這與PriorityQueue <E>的工作方式相同,只是具有線程安全的其他限定條件。
PriorityQueue <E>中定義的操作與Queue <E>相同,但有一些附加功能。
| 方法 |
描述 |
| void clear() |
從優先級隊列中刪除所有元素。 |
| Comparator<? Super E> comparator() |
返回與隊列關聯的比較器。如果根據自然順序對隊列進行排序,則返回null。 |
| boolean contains(Object o) |
如果隊列包含指定的對象,則返回true。 |
| Iterator<E> iterator() |
返回與Collection類關聯的舊式迭代器。但是,它不能保證以任何特定順序遍歷元素。 |
| Spliterator<E> spliterator() |
創建后期綁定,故障快速拆分器,但具有與迭代器相同的條件。 |
| Object[] toArray() |
這是一種便捷方法,可用於設置遍歷順序權限,例如Arrays.sort(priorityQueue.toArray()). |
| <T>T[] toArray(T[] a) |
返回數組元素,但是返回類型由指定的數組確定。 |
快速示例1
讓我們用一個簡單的程序實現PriorityQueue <E>的一些操作。
1 package org.mano.examples; 2 import java.util.Arrays; 3 import java.util.Iterator; 4 import java.util.PriorityQueue; 5 public class Example1 { 6 public static void main(String[] args){ 7 PriorityQueue<String> pq = new PriorityQueue<>(); 8 pq.add("Mercury"); 9 pq.add("Venus"); 10 pq.add("Earth"); 11 pq.add("Mars"); 12 pq.add("Jupiter"); 13 pq.add("Saturn"); 14 // Get the most priority element based upon 15 // natural alphabetic ordering in string 16 System.out.println("Priority element "+pq.peek()); 17 // Queue elements 18 show(pq); 19 // Remove top of the queue element 20 pq.poll(); 21 show(pq); 22 // Retrieves element from the head of the queue 23 pq.remove("Earth"); 24 show(pq); 25 String result = pq.contains("Earth")? 26 "Found Earth":"Earth Missing!"; 27 System.out.println(result); 28 Object[] arr = pq.toArray(); 29 Arrays.sort(arr); 30 System.out.println(""); 31 for (int i = 0; i<arr.length; i++) 32 System.out.print(arr[i].toString()+"::"); 33 } 34 public static void show(PriorityQueue<String> pq){ 35 Iterator<String> itr = pq.iterator(); 36 while (itr.hasNext()) 37 System.out.print(itr.next()+"::"); 38 System.out.println(""); 39 } 40 }
Output
1 Priority element Earth 2 Earth::Jupiter::Mercury::Venus::Mars::Saturn:: 3 Jupiter::Mars::Mercury::Venus::Saturn:: 4 Jupiter::Mars::Mercury::Venus::Saturn:: 5 Earth Missing! 6 7 Jupiter::Mars::Mercury::Saturn::Venus::
快速示例2
這是另一個帶有自定義比較器的快速示例。
1 package org.mano.examples; 2 import java.util.Comparator; 3 import java.util.PriorityQueue; 4 public class Planet implements Comparable<Planet>{ 5 private String name; 6 private double orbitPeriodInDays; 7 public Planet(String name, double orbitPeriodInDays) { 8 this.name = name; 9 this.orbitPeriodInDays = orbitPeriodInDays; 10 } 11 public String getName() { 12 return name; 13 } 14 public void setName(String name) { 15 this.name = name; 16 } 17 public double getOrbitPeriodInDays() { 18 return orbitPeriodInDays; 19 } 20 public void setOrbitPeriodInDays(double orbitPeriodInDays) { 21 this.orbitPeriodInDays = orbitPeriodInDays; 22 } 23 @Override 24 public int compareTo(Planet o) { 25 return 0; 26 } 27 @Override 28 public String toString() { 29 return "Planet{" + 30 "name='" + name + '\'' + 31 ", orbitPeriodInDays=" + orbitPeriodInDays + 32 '}'; 33 } 34 public static void main(String[] args){ 35 Comparator<Planet> nameSorter = 36 Comparator.comparing(Planet::getName); 37 PriorityQueue<Planet> priorityQueue = new 38 PriorityQueue<>(nameSorter); 39 priorityQueue.add(new Planet("Mercury",88)); 40 priorityQueue.add(new Planet("Venus",225)); 41 priorityQueue.add(new Planet("Earth",365.24)); 42 priorityQueue.add(new Planet("Mars",693.5)); 43 priorityQueue.add(new Planet("Jupiter",4343.5)); 44 priorityQueue.add(new Planet("Saturn",10767.5)); 45 priorityQueue.add(new Planet("Uranus",30660)); 46 priorityQueue.add(new Planet("Neptune",60152)); 47 Object[] list = priorityQueue.toArray(); 48 for (Object o: list) 49 System.out.println(o); 50 } 51 }
Output
1 Planet{name='Earth', orbitPeriodInDays=365.24} 2 Planet{name='Jupiter', orbitPeriodInDays=4343.5} 3 Planet{name='Mercury', orbitPeriodInDays=88.0} 4 Planet{name='Neptune', orbitPeriodInDays=60152.0} 5 Planet{name='Mars', orbitPeriodInDays=693.5} 6 Planet{name='Saturn', orbitPeriodInDays=10767.5} 7 Planet{name='Uranus', orbitPeriodInDays=30660.0} 8 Planet{name='Venus', orbitPeriodInDays=225.0}
總結
優先級隊列的其他規范是,從列表中刪除的項目具有最高優先級。Java將優先級規則強加給其他常規隊列的方式是通過附加元素的排序原則。該順序可以根據程序員的要求進行自定義,也可以設置為默認。這就是Java中優先級隊列實現的本質。
感謝閱讀!

