priorityQueue를 최대 priorityqueue로 변경


124

Java of Integers에 우선 순위 대기열이 있습니다.

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

전화 pq.poll()하면 최소 요소를 얻습니다.

질문 : 최대 요소를 얻기 위해 코드를 변경하는 방법은 무엇입니까?


4
이를 위해 비교기를받는 생성자를 사용해야한다고 생각합니다. Collections.reverseOrder를 사용하여 반전 된 비교기를 얻습니다.
Edwin Dalorzo 2012-06-12

1
비교기를 통과해야합니다. 참조 stackoverflow.com/questions/683041/…
DarthVader

답변:


232

다음과 같이 어떻습니까?

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()제공 Comparator의 요소 정렬 할 것이라고 PriorityQueue이 경우 자연 순서 a를 oposite 순서를.


14
Collections.reverseOrder()비교기를 가져 오기 위해 오버로드되기 때문에 사용자 지정 개체를 비교하는 경우에도 작동합니다.
날으는 양 '

14
Java 8의 PriorityQueue에는 comparator를 인수로 취하는 새로운 생성자가 PriorityQueue(Comparator<? super E> comparator)있습니다.
abhisheknirmal

75

Java 8부터 람다 식을 사용할 수 있습니다.

다음 코드는 더 큰 10을 인쇄합니다.

// 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());

람다 함수는 두 개의 정수를 입력 매개 변수로 취하고 서로 빼고 산술 결과를 반환합니다. 람다 함수는 기능 인터페이스 인 Comparator<T>. (이는 익명 클래스 또는 개별 구현과는 반대로 제자리에 사용됩니다.)


람다 함수는 입력 매개 변수 x와 y의 이름을 지정하고 yx를 반환합니다. 이는 기본적으로 xy를 반환하는 것을 제외하고는 int 비교기 클래스가 수행하는 작업입니다.
Edi Bice

15
같은 비교기 (x, y) -> y - x는 오버플로로 인해 긴 정수에 적합하지 않을 수 있습니다. 예를 들어, 숫자 y = Integer.MIN_VALUE 및 x = 5는 양수입니다. 사용하는 것이 좋습니다 new PriorityQueue<>((x, y) -> Integer.compare(y, x)). 하지만 더 나은 솔루션은 @Edwin Dalorzo가 Collections.reverseOrder().
Фима Гирин

1
@ ФимаГирин 사실입니다. -2147483648-1이 2147483647이 됨
Guangtong Shen

27

Comparator요소의 순위를 역순 으로 지정하는 사용자 지정 개체를 제공 할 수 있습니다 .

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;
    }
});

이제 우선 순위 큐는 모든 비교를 역순으로 수행하므로 최소 요소가 아닌 최대 요소를 얻을 수 있습니다.

도움이 되었기를 바랍니다!


5
최대 우선 순위 q의 경우 lhs <rhs는 +1을 반환합니다. 여기에 쓴 것은 내 테스트 후 최소 q입니다
sivi

역방향 인쇄의 경우, 즉 가장 높은 요소가 우선 순위 대기열에서 먼저 인쇄되는 경우 다음과 같아야합니다.if (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha 내가 가진 코드가 당신이 게시하는 것과 동일하다고 생각합니다. 나는보다 작다보다는보다 큼 관계를 사용했습니다.
templatetypedef

4
사실, 내 실수 .. 나는 그것이 다음과 같아야한다는 것을 의미했습니다 :if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu 좋은 캐치-이제 수정되었습니다!
templatetypedef

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

무엇이 문제입니까?
CMedina

이것은 완벽하며 최소 힙을 최대 힙으로 변환하여 요청한 작업을 정확히 수행합니다.
Kamran

2
사용하여 b-a발생할 수 overflow있으므로 것은 그것을 사용하지 않아야하고 사용한다 Collections.reverseOrder();비교기 나와 바 교체 Integer.compare(a,b);에 추가되었습니다Java 8
하기 Yug 싱

10

Java 8 이상에서는 다음 방법 중 하나를 통해 최대 우선 순위 대기열을 만들 수 있습니다.

방법 1 :

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

방법 2 :

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

방법 3 :

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

8

우선 순위 큐의 요소는 자연스러운 순서에 따라 또는 큐 생성시 제공되는 비교기에 의해 정렬됩니다.

비교기는 비교 방법을 재정의해야합니다.

int compare(T o1, T o2)

기본 비교 메서드는 첫 번째 인수가 두 번째 인수보다 작거나 같거나 크므로 음의 정수, 0 또는 양의 정수를 반환합니다.

Java에서 제공하는 기본 PriorityQueue는 Min-Heap입니다. 최대 힙을 원하는 경우 다음 코드가 있습니다.

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());
        }
    }

}

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


4

다음은 Java의 샘플 Max-Heap입니다.

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());

출력은 10입니다.


4

이는 비교기 만 사용하는 생성자를 도입 한 Java 8의 아래 코드에 의해 달성 될 수 있습니다.

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


3

PriorityQueue를 MAX PriorityQueue로 변경 방법 1 : 대기열 pq = new PriorityQueue <> (Collections.reverseOrder ()); 방법 2 : 대기열 pq1 = new PriorityQueue <> ((a, b)-> b-a); 몇 가지 예를 살펴 보겠습니다.

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

         */


    }
}

유명한 인터뷰 문제 : PriorityQueue를 사용하는 어레이에서 K 번째로 큰 요소

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

 */
    }
}

또 다른 방법 :

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

         */
    }
}

보시다시피, 둘 다 동일한 결과를 제공합니다.


3

이것은 다음을 사용하여 얻을 수 있습니다.

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

1

방금 double heap sort min max의 두 비교기에서 Monte-Carlo 시뮬레이션을 실행했는데 둘 다 동일한 결과를 얻었습니다.

다음은 내가 사용한 최대 비교기입니다.

(A) 컬렉션 내장 비교기

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

(B) 맞춤형 비교기

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;경우 if (rhs> lhs) return -1;
Tia

원하는 경우 편집 할 수 있습니다. 당신이 쓴 것을 확인할 시간이 없습니다. 내 설정에서 내가 쓴 내용이 정확했습니다
sivi

1

다음과 같이 시도 할 수 있습니다.

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

다른 기본 비교 기능에서 작동합니다.



0

역 기호로 요소를 밀어 볼 수 있습니다. 예 : a = 2 & b = 5를 추가 한 다음 b = 5를 폴링합니다.

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

대기열의 헤드를 폴링하면 사용량에 대한 기호를 뒤집습니다. 그러면 5 (더 큰 요소)가 인쇄됩니다. 순진한 구현에 사용할 수 있습니다. 확실히 신뢰할 수있는 수정이 아닙니다. 나는 그것을 추천하지 않는다.


0

Comparator 인터페이스를 구현하는 CustomComparator 클래스를 만들고 비교 메서드를 재정 의하여이를 수행 할 수 있습니다 . 다음은 동일한 코드입니다.

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;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.