Ö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.