Java Priorityqueue Comparator

Asked

Viewed 397 times

4

I’m trying to understand why the native mode of java is not performing the comparison, I don’t know where I’m going wrong.

MAIN

//  EXERCICIO PARA COMPARAR DOIS OBJETOS, USANDO CLASSE NATIVA DE COMPARAÇÃO DO JAVA

public static void main(String[] args) {
    FilaComPrioridade<Paciente> fila = new FilaComPrioridade<>();

    // CLASSE ANONIMA DENTRO DO NOSSO PROJETO.
    Queue<Paciente> filaComPrioridade = new PriorityQueue<>(new Comparator<Paciente>() {
        @Override
        public int compare(Paciente p1, Paciente p2) {
            return Integer.valueOf(p1.getPrioridade()).compareTo(p2.getPrioridade());
        }
    });

    filaComPrioridade.add(new Paciente("A", 2));
    filaComPrioridade.add(new Paciente("B1", 1));
    filaComPrioridade.add(new Paciente("B2", 1));
    filaComPrioridade.add(new Paciente("B3", 1));
    filaComPrioridade.add(new Paciente("B4", 1));
    filaComPrioridade.add(new Paciente("C", 3));

    fila.enfileira(new Paciente("A", 2));
    fila.enfileira(new Paciente("B1", 1));
    fila.enfileira(new Paciente("B2", 1));
    fila.enfileira(new Paciente("B3", 1));
    fila.enfileira(new Paciente("B4", 1));
    fila.enfileira(new Paciente("C", 3));

    System.out.println(filaComPrioridade);
    System.out.println(fila);
}

}

Imprint

[Patient [name=B1, priority=1], Patient [name=B3, priority=1], Patient [name=B2, priority=1], Patient [name=A, priority=2], Patient [name=B4, priority=1], Patient [name=C, priority=3]]

[Patient [name=B1, priority=1], Patient [name=B2, priority=1], Patient [name=B3, priority=1], Patient [name=B4, priority=1], Patient [name=A, priority=2], Patient [name=C, priority=3]]

Philanthropy class:

package pt.estruturadedados.base.fila;

public class FilaComPrioridade<T> extends Fila<T> {

    @Override
    public void enfileira(T elemento) {

        Comparable<T> chave = (Comparable<T>) elemento;

        int i;
        for (i = 0; i < this.tamanho; i++) {
            if (chave.compareTo(this.elementos[i]) < 0) {
                break;
            }
        }
        this.adiciona(i, elemento);
    }

}

CompareTo in the "NOT NATIVE" Manual Patient Class (Second Impression)

@Override
public int compareTo(Paciente o) {

    return Integer.valueOf(this.getPrioridade()).compareTo(o.getPrioridade()); //Forma mais elegante de fazer.
}

1 answer

9

I won’t know much about details, but here goes:

The method System.out.println() uses the method toString() of the Abstractcollection class and this, in turn, uses an Iterator (which is obtained by the method iterator() of the Priorityqueue itself). It turns out that the method iterator() of the Priorityqueue class does not guarantee the order of the elements in the queue.

Method documentation iterator():

Returns an iterator over the Elements in this Collection. There are no guarantees concerning the order in which the Elements are returned (unless this Collection is an instance of some class that provides a Guarantee).

However, if you use the methods of the Priorityqueue class itself to manipulate the elements they will be removed in the correct order, according to the predefined priority. Example:

Patient Class:

public class Paciente implements Comparable<Paciente> {

    private String nome;
    private int prioridade;

    public Paciente(String nome, int prioridade) {
        super();
        this.nome = nome;
        this.prioridade = prioridade;
    }

get and set methods for attributes...

    @Override
    public int compareTo(Paciente o) {
        if (this.prioridade > o.getPrioridade()) {
            return 1;
        } else if (this.prioridade < o.getPrioridade()) {
            return -1;
        }

        return 0;
    }

    @Override
    public String toString() {
        return "[" + nome + ", " + prioridade + "]";
    }

}

Class Duvidapriorityqueue:

import java.util.PriorityQueue;
import java.util.Queue;

public class DuvidaPriorityQueue {

    public static void main(String[] args) {

        Queue<Paciente> pqPac = new PriorityQueue<>();

        pqPac.add(new Paciente("A", 9));
        pqPac.add(new Paciente("B", 5));
        pqPac.add(new Paciente("C", 8));
        pqPac.add(new Paciente("D", 1));
        pqPac.add(new Paciente("E", 2));

        System.out.println(pqPac);//O que você fez

        System.out.println();

        //O que deveria ter feito:
        while(!pqPac.isEmpty()) {
            System.out.print(pqPac.poll() + ", ");
        }


    }

}

The output of this last class will be as follows:

[[D, 1], [E, 2], [C, 8], [A, 9], [B, 5]]

[D, 1], [E, 2], [B, 5], [C, 8], [A, 9],

Test trying to add the elements in another order. If you output the console using the methods of the Priorityqueue class itself as intermediaries, the priority you set will be obeyed. If you use the method System.out.println() direct on the Priorityqueue object you created, the result will vary.


Source (do not laugh):

Comments and responses from Ingrid Marçal and Devdojo in this video (and the tests I did to prove them): [Youtube]

  • 2

    Excellent answer, I learned something new. It is understandable that the PriorityQueue use a structure of heap internally, but honestly I find a design well severe API. It would be better to make a override of the method iterator() to return items in the correct order (making it clear to the user that the interaction time is not linear). What must it take for people to fall for pranks like for (Paciente p : filaComPrioridade) is not in the comic book.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.