J'utilise une PriorityQueue et mon propre comparateur mais, d'une manière ou d'une autre, les résultats finaux ne sont pas toujours bons… .. Je devrais trier par note, plutôt que par nom, par id.no. À la fin, les noms laissés dans la file d'attente doivent être retournés. Les noms restants sont corrects mais leur ordre n'est pas . Entrée (nom, grade moyen, id.no):
add John 3,75 50
add Mark 3,8 24
add Shafaet 3,7 35
poll
poll
add Samiha 3,85 36
poll
add Ashley 3,9 42
add Maria 3,6 46
add Anik 3,95 49
add Dan 3,95 50
poll
Production attendue:
Dan
Ashley
Shafaet
Maria
Mon résultat:
Dan
Ashley
Maria
Shafaet
Pourriez-vous s'il vous plaît m'aider à trouver le problème? Merci d'avance!
class StComp implements Comparator<Students> {
@Override
public int compare(Students st1, Students st2) {
if (st1.getCgpa() == st2.getCgpa()) {
if (st1.getName().equals(st2.getName()))
return st1.getId() - st2.getId();
else
return st1.getName().compareTo(st2.getName());
}
else
return (st1.getCgpa() < st2.getCgpa()) ? 1 : -1;
}
}
StComp stComp = new StComp();
PriorityQueue<Students> pq = new PriorityQueue<Students>(2, stComp);
Votre Comparator
est correcte. Le problème est que vous êtes probablement en train de parcourir la liste en utilisant sa Iterator
. La documentation PriorityQueue
déclare:
L’itérateur fourni dans la méthode iterator () n’est pas garanti.. parcourir les éléments de la file d'attente prioritaire dans un ordre particulier.
Si vous deviez parcourir votre PriorityQueue
comme ceci, vous devriez voir les résultats corrects:
while (!pq.isEmpty())
System.out.println(pq.poll().getName());
}
J'ai inclus un exemple à la fin de cette réponse pour démontrer pleinement.
Vous pouvez faire plusieurs choses si vous ne voulez pas effacer votre PriorityQueue
. Personnellement, je ne recommanderais aucune de ces approches car le choix initial de PriorityQueue
n'était pas correct pour le cas d'utilisation, car elles ne sont pas destinées à être itérées.
Vous pouvez copier votre PriorityQueue
dans un tableau, les trier à l'aide de votre implémentation Comparator
, effectuer une itération sur le tableau trié, par exemple:
Student[] students = pq.toArray(new Student[pq.size()]);
Arrays.sort(students, new StComp());
for (Student s : students) {
System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId());
}
ou ajoutez-les à une sorte de Collection
pendant l'interrogation, puis ajoutez-les à la PriorityQueue
, par exemple:
Collection<Student> temp = new LinkedList<>();
while (!pq.isEmpty()) {
Student s = pq.poll();
System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId());
temp.add(s);
}
pq.addAll(temp);
L'exemple utilisant vos données pour démontrer:
Principale
public class Main {
public static void main(String[] args) {
PriorityQueue<Student> pq = new PriorityQueue<>(new StComp());
pq.add(new Student("John", 75, 50)); // Student name, grade average, id
pq.add(new Student("Mark", 8, 24));
pq.add(new Student("Shafaet", 7, 35));
pq.poll();
pq.poll();
pq.add(new Student("Samiha", 85, 36));
pq.poll();
pq.add(new Student("Ashley", 9, 42));
pq.add(new Student("Maria", 6, 46));
pq.add(new Student("Anik", 95, 49));
pq.add(new Student("Dan", 95, 50));
pq.poll();
// Not guaranteed to be in priorty order
System.out.println("Using PriorityQueue's Iterator, may not be in the correct priority order.");
for (Student s : pq) {
System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId());
}
// Correct order, but removes from the Priority Queue
System.out.println("\nIterating until empty using PriorityQueue.poll(), will be in the correct order.");
while (!pq.isEmpty()) {
Student s = pq.poll();
System.out.println(s.getName() + " " + s.getCgpa() + " " + s.getId());
}
}
}
Student (renommé, devrait être singulier)
public class Student {
private double cgpa;
private String name;
private int id;
public Student(String name, double cgpa, int id) {
this.name = name;
this.cgpa = cgpa;
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public double getCgpa() {
return cgpa;
}
}
StComp (logique inchangée de la question)
public class StComp implements Comparator<Student> {
@Override
public int compare(Student st1, Student st2) {
if (st1.getCgpa() == st2.getCgpa()) {
if (st1.getName().equals(st2.getName())) {
return st1.getId() - st2.getId();
} else {
return st1.getName().compareTo(st2.getName());
}
} else {
return (st1.getCgpa() < st2.getCgpa()) ? 1 : -1;
}
}
}
Sortie (pour moi du moins, les résultats peuvent varier pour la première variante Iterator
)
Using PriorityQueue's Iterator, may not be in the correct priority order.
Dan 95.0 50
Ashley 9.0 42
Maria 6.0 46
Shafaet 7.0 35
Iterating until empty using PriorityQueue.poll(), will be in the correct order.
Dan 95.0 50
Ashley 9.0 42
Shafaet 7.0 35
Maria 6.0 46
A partir de Java 8, vous pouvez remplacer l’ensemble de votre classe de comparaison par ceci:
Comparator.comparingDouble(Students::getCgpa)
.thenComparing(Students::getName)
.thenComparingInt(Students::getId)
Si vous utilisez une version antérieure de Java ou si vous tenez à conserver le comparateur explicite, vous devez renvoyer zéro pour des valeurs égales. Vous devez également écrire votre comparateur pour qu'il soit cohérent avec equals. De la documentation :
L'ordre imposé par un comparateur
c
sur un ensemble d'élémentsS
est dit cohérent avec égal à si et seulement sic.compare(e1, e2)==0
a la même valeur booléenne quee1.equals(e2)
pour chaquee1
ete2
dansS
.Vous devez faire preuve de prudence lorsque vous utilisez un comparateur capable d'imposer un ordre incohérent avec égaux pour ordonner un ensemble trié (ou une carte triée). Supposons qu'un ensemble trié (ou une carte triée) avec un comparateur explicite
c
est utilisé avec des éléments (ou des clés) tirés d'un ensembleS
. Si l'ordre imposé parc
surS
est incohérent avec égaux, l'ensemble trié (ou la carte triée) se comportera "étrangement". En particulier, le jeu trié (ou la carte triée) violera le contrat général pour le jeu (ou la carte), défini en termes deequals
.
(En résumé, si deux objets sont égaux, le comparateur doit renvoyer zéro lorsqu'il les compare.)
@Override
public int compare(Students st1, Students st2) {
int comparison = Double.compare(st1.getCgpa(), st2.getCgpa());
if (comparison == 0) {
comparison = st1.getName().compareTo(st2.getName());
}
if (comparison == 0) {
comparison = st1.getId() - st2.getId();
}
return comparison;
}
Cela suppose que votre classe Students utilise une méthode equals
correspondante:
@Override
public boolean equals(Object obj) {
if (obj instanceof Students) {
Students other = (Students) obj;
return Double.compare(this.getCga(), other.getCga()) == 0
&& this.getName().equals(other.getName())
&& this.getId() == other.getId();
}
return false;
}