Nasıl PriorityQueue
sıralanmasını istediğimi sıralamak için nasıl alabilirim ?
Nasıl PriorityQueue
sıralanmasını istediğimi sıralamak için nasıl alabilirim ?
Yanıtlar:
Comparator<? super E> comparator
Sıralama düzeniniz için uygun şekilde karşılaştırılan bir karşılaştırıcıyı alan ve geçiren yapıcı aşırı yükünü kullanın . Nasıl sıralamak istediğinize ilişkin bir örnek verirseniz, emin değilseniz karşılaştırıcıyı uygulamak için bazı örnek kod sağlayabiliriz. (Yine de oldukça basit.)
Başka bir yerde söylendiği gibi: offer
ve add
sadece farklı arayüz yöntemi uygulamaları. JDK kaynağında, add
çağrılarım var offer
. Her ne kadar add
ve offer
sahip potansiyel yeteneğinin genel Due farklı davranış offer
değeri hacim sınırlamalarına bağlı olarak ilave edilemez olduğunu göstermek için, bu fark, önemli değildir PriorityQueue
olan sonsuz.
Dize uzunluğuna göre öncelik sırası sıralamasına bir örnek:
// Test.java
import java.util.Comparator;
import java.util.PriorityQueue;
public class Test {
public static void main(String[] args) {
Comparator<String> comparator = new StringLengthComparator();
PriorityQueue<String> queue = new PriorityQueue<String>(10, comparator);
queue.add("short");
queue.add("very long indeed");
queue.add("medium");
while (queue.size() != 0) {
System.out.println(queue.remove());
}
}
}
// StringLengthComparator.java
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String> {
@Override
public int compare(String x, String y) {
// Assume neither string is null. Real code should
// probably be more robust
// You could also just return x.length() - y.length(),
// which would be more efficient.
if (x.length() < y.length()) {
return -1;
}
if (x.length() > y.length()) {
return 1;
}
return 0;
}
}
İşte çıktı:
kısa
orta
gerçekten çok uzun
compare
Uygulama sadece değil return x.length() - y.length()
mi? (Şube tahmininden kaçınır)
add()
ekleme işlemi için kullanıyorsanız , o zaman remove()
mantıklı geliyor düşünüyorum; Eğer offer()
kullansaydım muhtemelen kullanardım poll()
... ama bu sadece kişisel bir tercih.
Java 8'i kullanabilir lambda expression
ya da kullanabiliriz method reference
. Öncelik Kuyruğunda saklanan bazı String değerlerimiz olması durumunda (kapasite 5'e sahip) satır içi karşılaştırıcı (String uzunluğuna bağlı olarak) sağlayabiliriz:
Lambda ifadesini kullanma
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Yöntem referansını kullanma
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
Sonra bunlardan herhangi birini kullanabiliriz:
public static void main(String[] args) {
PriorityQueue<String> pq=
new PriorityQueue<String>(5, (a,b) -> a.length() - b.length());
// or pq = new PriorityQueue<String>(5, Comparator.comparing(String::length));
pq.add("Apple");
pq.add("PineApple");
pq.add("Custard Apple");
while (pq.size() != 0)
{
System.out.println(pq.remove());
}
}
Bu yazdırılacak:
Apple
PineApple
Custard Apple
Sırayı tersine çevirmek (maksimum öncelik sırasına değiştirmek için), satır içi karşılaştırıcıdaki sırayı değiştirmeniz veya şu şekilde kullanmanız yeterlidir reversed
:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
Ayrıca şunları da kullanabiliriz Collections.reverseOrder
:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
Böylece Collections.reverseOrder
, özel nesneler için yararlı olabilecek karşılaştırıcı almak için aşırı yüklendiğini görebiliriz . reversed
Aslında kullanır Collections.reverseOrder
:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Doc başına
Teklif yöntemi mümkünse bir öğe ekler, aksi takdirde false değerini döndürür. Bu, yalnızca denetlenmeyen bir özel durum atarak öğe ekleyemeyen Collection.add yönteminden farklıdır. Teklif yöntemi, örneğin sabit kapasiteli (veya "sınırlı") kuyruklarda, olağandışı bir durumdan ziyade hata normal olduğunda kullanılmak üzere tasarlanmıştır.
Kapasite kısıtlı bir kuyruk kullanıldığında, offer () genellikle add () için tercih edilir, bu da sadece bir istisna atarak bir eleman ekleyemez. Ve PriorityQueue öncelik yığın dayalı bir sınırsız öncelikli kuyruk olduğunu.
5
kuyruk başlangıç kapasitesini gösterir varsayalım?
Sadece uygun düzgün geçmesi Comparator
için yapıcı :
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Arasındaki tek fark offer
ve add
ait oldukları arayüzüdür. offer
aittir Queue<E>
, oysa add
başlangıçta görülen Collection<E>
arayüz. Bunun dışında her iki yöntem de aynı şeyi yapar - belirtilen öğeyi öncelik sırasına ekleyin.
dan Kuyruk API :
Teklif yöntemi mümkünse bir öğe ekler, aksi takdirde false değerini döndürür. Bu, yalnızca denetlenmeyen bir özel durum atarak öğe ekleyemeyen Collection.add yönteminden farklıdır. Teklif yöntemi, örneğin sabit kapasiteli (veya "sınırlı") kuyruklarda, olağandışı bir durumdan ziyade hata normal olduğunda kullanılmak üzere tasarlanmıştır.
Sadece add()
vs offer()
sorusunu cevaplamak için (diğeri imo'ya mükemmel bir şekilde cevaplandığından ve bu olmayabilir):
Göre Sırasına arayüzü üzerinde JavaDoc'u , "teklif yöntemi aksi takdirde yanlış dönen bir eleman mümkünse ekler. Sadece işaretlenmemiş durum atarak bir eleman eklemek için başarısız olabilir Collection.add yönteminden farklı olması. Teklif yöntemi için tasarlanmış başarısızlık, olağan dışı bir durumdan ziyade normal bir durum olduğunda, örneğin sabit kapasiteli (veya "sınırlı") kuyruklarda kullanılır. "
Bu, öğeyi ekleyebileceğiniz anlamına gelir (bir PriorityQueue'da her zaman böyle olmalıdır), tam olarak aynı şekilde çalışırlar. Ancak öğeyi ekleyemezseniz, kodunuzda istemediğiniz kötü bir denetlenmeyen istisna atarken, offer()
size güzel ve güzel bir false
dönüş sağlar add()
. Eklenememesi, kodun amaçlandığı gibi çalıştığı anlamına gelirse ve / veya normal olarak kontrol edeceğiniz bir şeyse kullanın offer()
. Eklenememesi bir şeyin bozulduğu anlamına gelirse , Koleksiyon arayüzünün özelliklerineadd()
göre atılan istisnayı kullanın ve işleyin .
Her ikisi de, bir offer()
başarısızlık false
( kapasite kısıtlı kuyruklarda tercih edilen yöntem) döndürerek başarısızlıkları belirten Kuyruk arabirimindeki sözleşmeyi yerine getirmek ve ayrıca bir istisna atarak her zaman başarısız olduğunu belirtenadd()
sözleşmeyi korumak için bu şekilde uygulanır .
Her neyse, umarım bu sorunun en azından bir kısmını aydınlatır.
Burada, kullanıcı tanımlı karşılaştırıcıyı tanımlayabiliriz:
Aşağıdaki kod:
import java.util.*;
import java.util.Collections;
import java.util.Comparator;
class Checker implements Comparator<String>
{
public int compare(String str1, String str2)
{
if (str1.length() < str2.length()) return -1;
else return 1;
}
}
class Main
{
public static void main(String args[])
{
PriorityQueue<String> queue=new PriorityQueue<String>(5, new Checker());
queue.add("india");
queue.add("bangladesh");
queue.add("pakistan");
while (queue.size() != 0)
{
System.out.printf("%s\n",queue.remove());
}
}
}
Çıktı :
india pakistan bangladesh
Teklif ve ekleme yöntemleri arasındaki fark: bağlantı
Geçin a Comparator
. Yerine istediğiniz türü doldurunT
Lambdas kullanma (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Anonim sınıf kullanarak klasik yol:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
Ters sırada sıralamak için, sadece e1, e2'yi değiştirin.
Baskı siparişini de merak ediyordum. Bu durumu düşünün, örneğin:
Öncelik kuyruğu için:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
Bu kod:
pq3.offer("a");
pq3.offer("A");
aşağıdakilerden farklı baskı yapabilir:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
Bir kullanıcının "offer () / add () yöntemleri yalnızca öğeyi kuyruğa eklediğini söylediği başka bir forumdaki tartışmanın cevabını buldum . Tahmin edilebilir bir sipariş istiyorsanız, başını döndüren peek / anket kullanmalısınız ".
Kullanmaya alternatif olarak Comparator
, PriorityQueue
uygulamanızdaComparable
kullandığınız sınıfı da kullanabilirsiniz (ve buna karşılık olarak compareTo
yöntemi geçersiz kılabilirsiniz ).
Genellikle , bu sıralamanın nesnenin sezgisel sıralaması olması Comparable
yerine kullanılması en iyisidir Comparator
- örneğin, Person
nesneleri yaşa göre sıralamak için bir kullanım durumunuz varsa, muhtemelen Comparator
bunun yerine kullanmak en iyisidir .
import java.lang.Comparable;
import java.util.PriorityQueue;
class Test
{
public static void main(String[] args)
{
PriorityQueue<MyClass> queue = new PriorityQueue<MyClass>();
queue.add(new MyClass(2, "short"));
queue.add(new MyClass(2, "very long indeed"));
queue.add(new MyClass(1, "medium"));
queue.add(new MyClass(1, "very long indeed"));
queue.add(new MyClass(2, "medium"));
queue.add(new MyClass(1, "short"));
while (queue.size() != 0)
System.out.println(queue.remove());
}
}
class MyClass implements Comparable<MyClass>
{
int sortFirst;
String sortByLength;
public MyClass(int sortFirst, String sortByLength)
{
this.sortFirst = sortFirst;
this.sortByLength = sortByLength;
}
@Override
public int compareTo(MyClass other)
{
if (sortFirst != other.sortFirst)
return Integer.compare(sortFirst, other.sortFirst);
else
return Integer.compare(sortByLength.length(), other.sortByLength.length());
}
public String toString()
{
return sortFirst + ", " + sortByLength;
}
}
Çıktı:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
Öncelik Kuyruğu'nun her bir öğeye atanmış bir önceliği vardır; En yüksek önceliğe sahip öğe Sıranın Üstünde görünür. Şimdi, önceliğin her bir öğeye nasıl atanmasını istediğinize bağlı. Bunu yapmazsanız, Java bunu varsayılan şekilde yapar. En düşük değere sahip öğeye en yüksek öncelik atanır ve bu nedenle önce kuyruktan kaldırılır. Aynı en yüksek önceliğe sahip birkaç eleman varsa, kravat keyfi olarak kesilir. Ayrıca yapıcıdaki Karşılaştırıcı'yı kullanarak bir sipariş belirtebilirsiniz PriorityQueue(initialCapacity, comparator)
Örnek Kod:
PriorityQueue<String> queue1 = new PriorityQueue<>();
queue1.offer("Oklahoma");
queue1.offer("Indiana");
queue1.offer("Georgia");
queue1.offer("Texas");
System.out.println("Priority queue using Comparable:");
while (queue1.size() > 0) {
System.out.print(queue1.remove() + " ");
}
PriorityQueue<String> queue2 = new PriorityQueue(4, Collections.reverseOrder());
queue2.offer("Oklahoma");
queue2.offer("Indiana");
queue2.offer("Georgia");
queue2.offer("Texas");
System.out.println("\nPriority queue using Comparator:");
while (queue2.size() > 0) {
System.out.print(queue2.remove() + " ");
}
Çıktı:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
Else, Özel Karşılaştırıcıyı da tanımlayabilirsiniz:
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
@Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
İlk öğrenme için kullanabileceğiniz basit örnek:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
public class PQExample {
public static void main(String[] args) {
//PriorityQueue with Comparator
Queue<Customer> cpq = new PriorityQueue<>(7, idComp);
addToQueue(cpq);
pollFromQueue(cpq);
}
public static Comparator<Customer> idComp = new Comparator<Customer>(){
@Override
public int compare(Customer o1, Customer o2) {
return (int) (o1.getId() - o2.getId());
}
};
//utility method to add random data to Queue
private static void addToQueue(Queue<Customer> cq){
Random rand = new Random();
for(int i=0;i<7;i++){
int id = rand.nextInt(100);
cq.add(new Customer(id, "KV"+id));
}
}
private static void pollFromQueue(Queue<Customer> cq){
while(true){
Customer c = cq.poll();
if(c == null) break;
System.out.println("Customer Polled : "+c.getId() + " "+ c.getName());
}
}
}