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?
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?
Yanıtlar:
Ş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 PriorityQueue
bu durumda doğal düzene bir oposite sırayla.
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.
PriorityQueue(Comparator<? super E> comparator)
.
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.)
(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()
.
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!
if (rhs < lhs) return +1;
if (rhs > lhs) return -1;
if (lhs < rhs) return +1; if (lhs > rhs) return -1;
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
new Comparator<Integer> () {
public int compare(Integer a, Integer b) {
return b - a;
}
}
);
b-a
neden olabilir, overflow
bu 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
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));
Ö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 ()
İş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
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());
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()
.
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.
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;
}
});
if (rhs < lhs) return +1;
eğer (rhs> lhs) -1 döndürürse;
Ş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.
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));
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.
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;
}
}