優先順序佇列是一種什麼樣的資料結構

lengtianxue發表於2016-09-07

http://www.importnew.com/6510.html


優先順序佇列(PriprityQueue)是一種無界佇列,基於優先順序堆,它的元素根據自然順序或者通過實現Comparator介面的自定義排序方式進行排序。這篇文章,我們將建立一個Items的優先順序佇列,基於價格排序,優先順序佇列用來實現迪科斯徹演算法(Dijkstra algorithm)非常實用。值得注意的是他的迭代器並不保證有序,如果需要按順序遍歷,最好使用Arrays.sort(pd.toArray())方法。同時它的實現不是同步的,意味著在多執行緒中不是執行緒安全的物件,可以取而代之的是PriorityBlockingQueue,它能用於多執行緒環境。優先順序佇列提供了O(log(n))時間在出隊和入隊的方法上,比如:offer(),poll(),add(),但是對於檢索操作如:peek(),element()提供的是常量(固定)時間。

如何使用PriorityQueue

這裡是如何使用PriorityQueue的一個例子,如上所說,你可以使用特定的順序來組織元素,可以是自然順序或者元素實現Comparator介面,這個例子中,我們把Items物件放入優先順序佇列中,按照價格排序,你可以注意下Item類的compareTo方法,它與equals方法是保持一致的,這裡把Item類作為內部靜態類,把item儲存在優先順序佇列中,你可以一直使用poll()方法獲取價格最低的那個item。

import java.util.PriorityQueue;
import java.util.Queue;

public class test2 {

	public static void main(String args[]) {
		 
        Queue<Item> items = new PriorityQueue<Item>();
        items.add(new Item("IPone", 900));
        items.add(new Item("IPad", 1200));
        items.add(new Item("Xbox", 300));
        items.add(new Item("Watch", 200));
 
        System.out.println("Order of items in PriorityQueue");
        System.out.println(items);
 
        System.out.println("Element consumed from head of the PriorityQueue : " + items.poll());
        System.out.println(items);
 
        System.out.println("Element consumed from head of the PriorityQueue : " + items.poll());
        System.out.println(items);
 
        System.out.println("Element consumed from head of the PriorityQueue : " + items.poll());
        System.out.println(items);
 
        //items.add(null); // null elements not allowed in PriorityQueue - NullPointerException
 
    }
 
    private static class Item implements Comparable<Item> {
 
        private String name;
        private int price;
 
        public Item(String name, int price) {
            this.name = name;
            this.price = price;
        }
 
        public String getName() {
            return name;
        }
 
        public int getPrice() {
            return price;
        }
 
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Item other = (Item) obj;
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }
            if (this.price != other.price) {
                return false;
            }
            return true;
        }
 
        @Override
        public int hashCode() {
            int hash = 5;
            hash = hash + (this.name != null ? this.name.hashCode() : 0);
            hash = hash + this.price;
            return hash;
        }
 
        @Override
        public int compareTo(Item i) {
            if (this.price == i.price) {
                return this.name.compareTo(i.name);
            }
 
            return this.price - i.price;
        }
 
        @Override
        public String toString() {
            return String.format("%s: $%d", name, price);
        }      
 
    }
}


output:

Order of items in PriorityQueue
 
[Watch: $200, Xbox: $300, IPone: $900, IPad: $1200]
Element consumed from head of the PriorityQueue : Watch: $200
 
[Xbox: $300, IPad: $1200, IPone: $900]
Element consumed from head of the PriorityQueue : Xbox: $300
 
[IPone: $900, IPad: $1200]
Element consumed from head of the PriorityQueue : IPone: $900
 
[IPad: $1200]

從上面的輸出結果可以很清晰的看到優先順序物件始終把最小的值儲存在頭部,它的排序規則取決於compareTo()方法,儘管它不一定所有元素都是按序排列的,但是它能保證佇列的頭一定是最小的元素,這也是TreeSet和PriorityQueue的區別,前者能保證所有元素按序排列,而優先順序佇列僅僅保證列的頭是有序的,另一個需要注意的地方是PriorityQueue並不允許null元素存在,如果嘗試新增null值,那麼就會丟擲NullPointException異常:

Exception in thread "main" java.lang.NullPointerException
        at java.util.PriorityQueue.offer(PriorityQueue.java:265)
        at java.util.PriorityQueue.add(PriorityQueue.java:251)
        at test.PriorityQueueTest.main(PriorityQueueTest.java:36)
Java Result: 1

總結:

和所有其他集合類一樣,值得注意一下幾點:

  1. 優先順序佇列不是同步的,如果需要保證執行緒安全那麼請使用PriorityBlockingQueue
  2. 佇列的獲取操作如poll(),peek()和element()是訪問的佇列的頭,保證獲取的是最小的元素(根據指定的排序規則)
  3. 返回的迭代器並不保證提供任何的有序性
  4. 優先順序佇列不允許null元素,否則丟擲NullPointException。

以上所有就是有關優先順序佇列的全部,它是一個很特別的類,用在一些特性的情景。記住:BlockingQueue維持的是插入的順序,如果想維持自定義的順序PriorityQueue或者PriorityBlockingQueue是正確的選擇,TreeSet提供類似的功能,但是沒有類似的檢索+移除的方法:poll()



相關文章