Alterar priorityQueue para max priorityqueue


124

Tenho fila de prioridade em Java de inteiros:

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

Quando ligo pq.poll(), obtenho o elemento mínimo.

Pergunta: como alterar o código para obter o elemento máximo?


4
Acho que você deve usar o construtor que recebe um comparador para isso. Use o Collections.reverseOrder para obter um comparador reverso.
Edwin Dalorzo

1
você precisa passar por um comparador. consulte stackoverflow.com/questions/683041/…
DarthVader

Respostas:


232

Que tal assim:

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

O Collections.reverseOrder()fornece uma Comparatorque classificaria os elementos em PriorityQueueuma ordem oposta à sua ordem natural neste caso.


14
Collections.reverseOrder()também está sobrecarregado para obter um comparador, portanto, também funciona se você comparar objetos personalizados.
ovelhas voadoras

14
PriorityQueue do Java 8 tem um novo construtor, que apenas usa o comparador como argumento PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal

75

Você pode usar a expressão lambda desde Java 8.

O código a seguir imprimirá 10, o maior.

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

A função lambda pegará dois inteiros como parâmetros de entrada, os subtrairá um do outro e retornará o resultado aritmético. A função lambda implementa a Interface Funcional Comparator<T>,. (Isso é usado no local, ao contrário de uma classe anônima ou uma implementação discreta.)


função lambda, nomeia seus parâmetros de entrada xey e retorna yx, que é basicamente o que a classe comparadora int faz, exceto que retorna xy
Edi Bice

15
O comparador (x, y) -> y - xpode não ser apropriado para inteiros longos devido ao estouro. Por exemplo, os números y = Integer.MIN_VALUE ex = 5 resultam em um número positivo. É melhor usar new PriorityQueue<>((x, y) -> Integer.compare(y, x)). Porém, a melhor solução é dada por @Edwin Dalorzo para uso Collections.reverseOrder().
Фима Гирин

1
@ ФимаГирин Isso é verdade. -2147483648-1 torna-se 2147483647
Guangtong Shen

27

Você pode fornecer um Comparatorobjeto personalizado que classifica os elementos na ordem inversa:

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

Agora, a fila de prioridade inverterá todas as suas comparações, de modo que você obterá o elemento máximo em vez do elemento mínimo.

Espero que isto ajude!


5
talvez para uma prioridade máxima q o lhs <rhs retorna +1; o que você escreveu aqui é o mínimo q após meu teste
sivi

Para impressão reversa, isto é, se os elementos mais altos forem impressos primeiro em uma fila de prioridade, deve serif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha Acredito que o código que tenho é equivalente ao que você está postando. Acabei de usar a relação maior que em vez de menor que.
templatetypedef de

4
na verdade, erro meu .. Eu quis dizer que deveria ser assim:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu Boa pegada - agora corrigido!
templatetypedef

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

Qual é o problema ?
CMedina

Isso é perfeito e faz exatamente o que foi pedido, transformando um heap mínimo em um heap máximo.
Kamran

2
usar b-apode causar, overflowentão deve evitar usá-lo e deve usar Collections.reverseOrder();como um comparador ou substituir ba com o Integer.compare(a,b);qual foi adicionado emJava 8
Yug Singh

10

No Java 8+, você pode criar uma fila de prioridade máxima por meio de um destes métodos:

Método 1:

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

Método 2:

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

Método 3:

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

8

Os elementos da fila de prioridade são ordenados de acordo com sua ordem natural ou por um Comparador fornecido no momento da construção da fila.

O Comparador deve substituir o método de comparação.

int compare(T o1, T o2)

O método de comparação padrão retorna um número inteiro negativo, zero ou um número inteiro positivo, pois o primeiro argumento é menor, igual ou maior que o segundo.

O PriorityQueue padrão fornecido por Java é Min-Heap, se você quiser um heap máximo a seguir está o código

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

}

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


4

Aqui está um exemplo de Max-Heap em Java:

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

A saída será 10


4

Isso pode ser alcançado pelo código abaixo em Java 8, que introduziu um construtor que usa apenas um comparador.

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


3

Altere PriorityQueue para MAX PriorityQueue Método 1: Queue pq = new PriorityQueue <> (Collections.reverseOrder ()); Método 2: Fila pq1 = new PriorityQueue <> ((a, b) -> b - a); Vejamos alguns exemplos:

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

         */


    }
}

Vamos dar um famoso problema de entrevista: Kth maior elemento em uma matriz usando PriorityQueue

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

 */
    }
}

Outra maneira:

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

         */
    }
}

Como podemos ver, ambos estão dando o mesmo resultado.


3

Isso pode ser alcançado usando

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

1

Acabei de executar uma simulação de Monte-Carlo em ambos os comparadores em classificação de pilha dupla mín. Máx. E ambos chegaram ao mesmo resultado:

Estes são os comparadores máximos que usei:

(A) Comparador integrado de coleções

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

(B) Comparador personalizado

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

Para impressão reversa, isto é, se os elementos mais altos devem ser impressos primeiro em uma fila de prioridade, deve ser if (rhs < lhs) return +1;if (rhs> lhs) return -1;
Tia de

Você pode editá-lo se quiser. Não tenho tempo para confirmar o que você escreveu. Na minha configuração, o que escrevi estava correto
sivi

1

Você pode tentar algo como:

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

Que funciona para qualquer outra função de comparação de base que você possa ter.


1
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));

0

Você pode tentar empurrar elementos com sinal reverso. Por exemplo: para adicionar a = 2 & b = 5 e, em seguida, pesquisar b = 5.

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

Depois de consultar o chefe da fila, inverta o sinal para o seu uso. Isso imprimirá 5 (elemento maior). Pode ser usado em implementações ingênuas. Definitivamente, não é uma solução confiável. Eu não recomendo.


0

Podemos fazer isso criando nossa classe CustomComparator que implementa a interface Comparator e substituindo seu método de comparação. Abaixo está o código para o mesmo:

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;
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.