Java 中的 PriorityQueue iterator() 方法
一、簡介
PriorityQueue
中的基本方法之一是iterator()
方法。此方法允許無縫遍歷儲存在佇列中的元素。在本教程中,我們將探索iterator()
方法的功能並示範其在各種場景中的有效使用。
2. PriorityQueue
概述
Java 中的PriorityQueue
類別充當資料結構,允許根據元素的優先權將元素儲存在佇列中。
PriorityQueue
內部使用二元堆,這是一種樹狀結構,其中元素根據優先順序進行排列。最高優先權元素駐留在根節點,子節點繼承其父節點的優先權。這種安排確保最高優先順序的元素位於前面,而最低優先順序的元素位於後面。
此外, PriorityQueue
類別實作了Queue
接口,並提供了一系列用於操作佇列中元素的方法,包括iterator()
方法。 iterator()
方法是Iterable
介面的一部分,用來取得元素集合的迭代器。 iterator()
方法的簽章定義為:
public Iterator<E> iterator()
iterator()
方法傳回佇列中元素的Iterator
。參數E
的類型指定佇列中元素的類型。此方法不帶任何參數
3. Iterator
特性
讓我們深入研究一下迭代器的關鍵特性:
3.1.快速失敗保證
iterator()
方法傳回的迭代器是一個快速失敗迭代器。這意味著如果我們在使用迭代器時嘗試修改佇列(新增或刪除元素),則會拋出ConcurrentModificationException
。此行為可確保迭代器始終反映佇列的目前狀態。
在程式碼中,我們在獲得迭代器後透過新增一個元素來修改PriorityQueue
:
PriorityQueue<Integer> numbers = new PriorityQueue<>();
numbers.add(3);
numbers.add(1);
numbers.add(2);
Iterator<Integer> iterator = numbers.iterator();
numbers.add(4);
try {
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
} catch (ConcurrentModificationException e) {
System.out.println("ConcurrentModificationException occurred during iteration.");
}
該程式的輸出將是:
ConcurrentModificationException occurred during iteration.
3.2.遍歷順序
iterator()
方法以特定的方式遍歷堆結構,通常基於層序遍歷方法。這意味著它從堆的頂部開始向下逐級存取元素。這種方法對於存取元素是有效的,但可能不會總是產生嚴格基於優先順序的順序。
讓我們來看一個如何使用iterator()
方法迭代PriorityQueue
中的元素的範例:
PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.add(3);
queue.add(1);
queue.add(2);
Iterator<Integer> iterator = queue.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
System.out.println(element);
}
在此範例中,我們建立一個整數PriorityQueue
並在其中新增三個元素。然後,我們取得佇列中元素的迭代器,並使用while
循環迭代元素,將每個元素列印到控制台。該程式的輸出將是:
1
3
2
在內部, PriorityQueue
看起來像:
1
/ \
3 2
在迭代期間,迭代器按級別順序遍歷元素,產生順序 1、3 和 2。雖然此順序保持了堆的一般結構,但它並不嚴格遵守基於優先權的排序。
4. Comparator
接口
在某些情況下,我們可能希望根據自訂標準對PriorityQueue
中的元素進行排序。這可以透過利用Comparator
介面來實現。此介面允許我們定義一個比較函數,可用於對佇列中的元素進行排序。
Comparator
介面有一個compare()
方法,該方法接受兩個相同類型的參數並傳回一個整數值。 compare()
方法傳回的值決定佇列中元素的順序。
讓我們考慮以下範例,其中我們有一個Person
類,要求是根據個人的年齡對他們進行優先排序。為了解決這個問題,我們將建立一個自訂比較器:
class PersonAgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.age - p2.age;
}
}
隨後,我們將建立一個具有自訂排序的PriorityQueue
。我們需要將PersonAgeComparator
介面的實例傳遞給PriorityQueue
的建構子。然後佇列中的元素將根據Comparator
定義的比較函數進行排序:
PriorityQueue<Person> priorityQueue = new PriorityQueue<>(new PersonAgeComparator());
priorityQueue.add(new Person("Alice", 25));
priorityQueue.add(new Person("Bob", 30));
priorityQueue.add(new Person("Charlie", 22));
Iterator<Person> iterator = priorityQueue.iterator();
while (iterator.hasNext()) {
Person person = iterator.next();
System.out.println("Name: " + person.name + ", Age: " + person.age);
}
該程式的輸出將是:
Name: Charlie, Age: 22
Name: Bob, Age: 30
Name: Alice, Age: 25
5.有序檢索
即使我們使用了自訂Comparator
,前面的範例也沒有按照嚴格的年齡升序顯示元素。 PriorityQueue
的內部結構可能會導致直接迭代期間出現意外結果。這是因為迭代器遵循層級順序遍歷,這會導致迭代期間的順序不同,因為它逐級存取元素。
為了確保元素按照其優先順序的確切順序檢索,我們可以使用poll()
方法。此方法專門從PriorityQueue
中刪除具有最高優先權(在本例中為最低年齡)的元素並將其傳回。
讓我們看看如何使用poll()
方法按順序檢索元素:
while (!priorityQueue.isEmpty()) {
Person person = priorityQueue.poll();
System.out.println("Name: " + person.name + ", Age: " + person.age);
}
該程式的輸出現在將是:
Name: Charlie, Age: 22
Name: Alice, Age: 25
Name: Bob, Age: 30
6. 使用案例
儘管iterator()
可能不適合嚴格排序的檢索,但它在優先順序不重要的情況下表現出色 - 例如,在PriorityQueue
中大寫人名或計算平均年齡等統計數據,而不考慮優先順序。讓我們用一個例子來說明用例:
while (iterator.hasNext()) {
Person person = iterator.next();
person.setName(person.getName().toUpperCase());
}
七、結論
在本文中,我們探討了 Java 中的PriorityQueue
類,強調了iterator()
方法的作用。需要注意的是,雖然PriorityQueue
在內部維護排序順序, iterator()
方法並不保證按該順序進行遍歷。因此,我們使用iterator()
方法來執行不依賴優先權順序的操作。
與往常一樣,程式碼可以在 GitHub 上取得。