Önceliği değiştir Kuyruğu maksimum öncelik sırasına


125

Java Integers'da öncelik kuyruğum var:

 PriorityQueue<Integer> pq= new PriorityQueue<Integer>();

Aradığımda pq.poll() asgari unsuru alırım.

Soru: Maksimum elemanı elde etmek için kod nasıl değiştirilir?


5
Bunun için bir karşılaştırıcı alan kurucuyu kullanmanız gerektiğini düşünüyorum. Tersine çevrilmiş bir karşılaştırıcı elde etmek için Collections.reverseOrder'ı kullanın.
Edwin Dalorzo

1
bir karşılaştırıcıyı geçmeniz gerekiyor. stackoverflow.com/questions/683041/…
DarthVader

Bu yardımcı olabilir: tech693.blogspot.com/2018/09/…
Java Guru

Yanıtlar:


233

Şuna ne dersin:

PriorityQueue<Integer> queue = new PriorityQueue<>(10, Collections.reverseOrder());
queue.offer(1);
queue.offer(2);
queue.offer(3);
//...

Integer val = null;
while( (val = queue.poll()) != null) {
    System.out.println(val);
}

Collections.reverseOrder()Bir sağlamaktadır Comparatoröğeleri sıralamak edeceğini PriorityQueuebu durumda doğal düzene bir oposite sırayla.


14
Collections.reverseOrder()bir karşılaştırıcı almak için aşırı yüklendiğinden, özel nesneleri karşılaştırdığınızda da çalışır.
uçan koyun

14
Java 8'in PriorityQueue'su, karşılaştırıcıyı argüman olarak alan yeni bir kurucuya sahiptir PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal

75

Lambda ifadesini Java 8'den beri kullanabilirsiniz.

Aşağıdaki kod, daha büyük olan 10'u basacaktır.

// There is overflow problem when using simple lambda as comparator, as pointed out by Фима Гирин.
// PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> y - x);

PriorityQueue<Integer> pq =new PriorityQueue<>((x, y) -> Integer.compare(y, x));

pq.add(10);
pq.add(5);
System.out.println(pq.peek());

Lambda işlevi, girdi parametreleri olarak iki Tamsayı alır, bunları birbirlerinden çıkarır ve aritmetik sonucu döndürür. Lambda işlevi, İşlevsel Arabirimi uygular Comparator<T>. (Bu, anonim bir sınıfın veya ayrı bir uygulamanın aksine yerinde kullanılır.)


lambda fonksiyonu, isimler onun giriş parametreleri x ve y ve iadeler YX, bu xy döndürmesi dışında int karşılaştırıcı sınıfı ne temelde hangi
Edi Bice

15
Benzeri karşılaştırıcı (x, y) -> y - x, taşma nedeniyle uzun tamsayılar için uygun olmayabilir. Örneğin, y = Tamsayı.MIN_VALUE ve x = 5 sayıları pozitif sayı ile sonuçlanır. Kullanması daha iyidir new PriorityQueue<>((x, y) -> Integer.compare(y, x)). Yine de, daha iyi bir çözüm kullanmak için @Edwin Dalorzo tarafından verilmiştir Collections.reverseOrder().
Фима Гирин

1
@ ФимаГирин Bu doğru. -2147483648 - 1, 2147483647 olur
Guangtong Shen

27

ComparatorÖğeleri ters sırada sıralayan özel bir nesne sağlayabilirsiniz:

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(defaultSize, new Comparator<Integer>() {
    public int compare(Integer lhs, Integer rhs) {
        if (lhs < rhs) return +1;
        if (lhs.equals(rhs)) return 0;
        return -1;
    }
});

Şimdi, öncelik sırası tüm karşılaştırmalarını tersine çevirecek, böylece minimum öğe yerine maksimum öğeyi elde edeceksiniz.

Bu yardımcı olur umarım!


5
belki maksimum öncelik q için lhs <rhs +1 döndürür; burada yazdıklarınız testlerimden sonra minimum q
sivi

Ters baskı için, yani bir öncelik kuyruğunda en yüksek öğeler önce yazdırılacaksa, bu şu olmalıdırif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha Sahip olduğum kodun gönderdiğiniz kodla eşdeğer olduğuna inanıyorum. Azdan çok yerine büyük ilişkisini kullandım.
templatetypedef

4
aslında benim hatam .. Bunun böyle olması gerektiğini söyledim:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu İyi yakalama - bu şimdi düzeltildi!
templatetypedef

14
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
  new Comparator<Integer> () {
    public int compare(Integer a, Integer b) {
       return b - a;
    }
  }
);

Sorun nedir ?
CMedina

Bu mükemmel ve en küçük bir yığını maksimum yığına dönüştürerek tam olarak istenen şeyi yapıyor.
Kamran

2
kullanımı b-aneden olabilir, overflowbu yüzden kullanmaktan kaçınmalı ve Collections.reverseOrder();bir karşılaştırıcı olarak kullanılmalı veya Integer.compare(a,b);eklenen ba ile değiştirilmelidirJava 8
Yug Singh

10

Java 8+ sürümünde, aşağıdaki yöntemlerden birini kullanarak bir maksimum öncelik sırası oluşturabilirsiniz:

Yöntem 1:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Collections.reverseOrder()); 

Yöntem 2:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b - a); 

Yöntem 3:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b.compareTo(a)); 

8

Öncelik kuyruğunun öğeleri, doğal sıralarına göre veya kuyruk oluşturma zamanında sağlanan bir Karşılaştırıcı tarafından sıralanır.

Karşılaştırıcı, karşılaştırma yöntemini geçersiz kılmalıdır.

int compare(T o1, T o2)

İlk bağımsız değişken ikinciden küçük, ona eşit veya daha büyük olduğu için varsayılan karşılaştırma yöntemi negatif bir tamsayı, sıfır veya pozitif bir tamsayı döndürür.

Java tarafından sağlanan Varsayılan PriorityQueue, Min-Heap'dir, eğer maksimum yığın istiyorsanız, aşağıdaki koddur

public class Sample {
    public static void main(String[] args) {
        PriorityQueue<Integer> q = new PriorityQueue<Integer>(new Comparator<Integer>() {

            public int compare(Integer lhs, Integer rhs) {
                if(lhs<rhs) return +1;
                if(lhs>rhs) return -1;
                return 0;
            }
        });
        q.add(13);
        q.add(4);q.add(14);q.add(-4);q.add(1);
        while (!q.isEmpty()) {
            System.out.println(q.poll());
        }
    }

}

Referans: https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#comparator ()


4

İşte Java'da bir Max-Heap örneği:

PriorityQueue<Integer> pq1= new PriorityQueue<Integer>(10, new Comparator<Integer>() {
public int compare(Integer x, Integer y) {
if (x < y) return 1;
if (x > y) return -1;
return 0;
}
});
pq1.add(5);
pq1.add(10);
pq1.add(-1);
System.out.println("Peek: "+pq1.peek());

Çıktı 10 olacak


4

Bu, yalnızca bir karşılaştırıcı alan bir kurucu getiren Java 8'deki aşağıdaki kodla sağlanabilir.

PriorityQueue<Integer> maxPriorityQ = new PriorityQueue<Integer>(Collections.reverseOrder());

3

Kullanabilirsiniz MinMaxPriorityQueue(bu, Guava kütüphanesinin bir parçasıdır): işte belgeler . Bunun yerine yöntemi poll()çağırmanız gerekir pollLast().


3

PriorityQueue'yu MAX PriorityQueue Yöntem 1'e Değiştirin: Queue pq = new PriorityQueue <> (Collections.reverseOrder ()); Yöntem 2: Kuyruk pq1 = yeni PriorityQueue <> ((a, b) -> b - a); Birkaç Örneğe bakalım:

public class Example1 {
    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        pq.addAll(ints);
        System.out.println("Priority Queue => " + pq);
        System.out.println("Max element in the list => " + pq.peek());
        System.out.println("......................");
        // another way
        Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
        pq1.addAll(ints);
        System.out.println("Priority Queue => " + pq1);
        System.out.println("Max element in the list => " + pq1.peek());
        /* OUTPUT
          Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
          Max element in the list => 888
          ......................
           Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
           Max element in the list => 888

         */


    }
}

Ünlü bir röportaj yapalım Problem: PriorityQueue kullanarak bir Array'deki Kth En Büyük Eleman

public class KthLargestElement_1{
    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        int k = 3;
        Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        pq.addAll(ints);
        System.out.println("Priority Queue => " + pq);
        System.out.println("Max element in the list => " + pq.peek());
        while (--k > 0) {
            pq.poll();
        } // while
        System.out.println("Third largest => " + pq.peek());
/*
 Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
Third largest => 666

 */
    }
}

Diğer yol :

public class KthLargestElement_2 {
    public static void main(String[] args) {
        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        int k = 3;

        Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
        pq1.addAll(ints);
        System.out.println("Priority Queue => " + pq1);
        System.out.println("Max element in the list => " + pq1.peek());
        while (--k > 0) {
            pq1.poll();
        } // while
        System.out.println("Third largest => " + pq1.peek());
        /*
          Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222] 
          Max element in the list => 888 
          Third largest => 666

         */
    }
}

Gördüğümüz gibi ikisi de aynı sonucu veriyor.


3

Bu, kullanılarak elde edilebilir

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());

1

Az önce her iki karşılaştırıcıda da çift yığın sıralama minimum maks. Değerinde bir Monte-Carlo simülasyonu çalıştırdım ve ikisi de aynı sonuca ulaştı:

Bunlar kullandığım maksimum karşılaştırıcılar:

(A) Yerleşik karşılaştırıcı koleksiyonlar

 PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(Collections.reverseOrder());

(B) Özel karşılaştırıcı

PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(new Comparator<Integer>() {
    int compare(Integer lhs, Integer rhs) {
        if (rhs > lhs) return +1;
        if (rhs < lhs) return -1;
        return 0;
    }
});

Ters baskı için, yani bir öncelik kuyruğunda en yüksek elemanlar önce yazdırılacaksa, if (rhs < lhs) return +1;eğer (rhs> lhs) -1 döndürürse;
Tia

İsterseniz düzenleyebilirsiniz. Yazdıklarınızı doğrulayacak vaktim yok. Kurulumumda yazdıklarım doğruydu
sivi

1

Şunun gibi bir şey deneyebilirsiniz:

PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> -1 * Integer.compare(x, y));

Sahip olabileceğiniz diğer herhangi bir temel karşılaştırma işlevi için çalışır.



0

Ters işaretli öğeleri itmeyi deneyebilirsiniz. Örneğin: a = 2 & b = 5 ve ardından b = 5 anketi eklemek için.

PriorityQueue<Integer>  pq = new PriorityQueue<>();
pq.add(-a);
pq.add(-b);
System.out.print(-pq.poll());

Sıranın başını yokladıktan sonra, kullanımınız için işareti ters çevirin. Bu 5 (daha büyük eleman) yazdıracaktır. Saf uygulamalarda kullanılabilir. Kesinlikle güvenilir bir çözüm değil. Ben tavsiye etmiyorum.


0

Bunu, Comparator arayüzünü uygulayan CustomComparator sınıfımızı oluşturarak ve karşılaştırma yöntemini geçersiz kılarak yapabiliriz. Aynı kod aşağıdadır:

import java.util.PriorityQueue;
import java.util.Comparator;
public class Main
{
    public static void main(String[] args) {
        PriorityQueue<Integer> nums = new PriorityQueue<>(new CustomComparator());
        nums.offer(21);
        nums.offer(1);
        nums.offer(8);
        nums.offer(2);
        nums.offer(-4);
        System.out.println(nums.peek());
    }
}
class CustomComparator implements Comparator<Integer>{
    @Override
    public int compare(Integer n1, Integer n2){
        int val = n1.compareTo(n2);
        if(val > 0)
           return -1;
        else if(val < 0)
            return 1;
        else
            return 0;
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.