具有自定义比较器的Java PriorityQueue

我使用的是PriorityQueue和我自己的比较器,但不知怎的,最终结果并不总是好的。 我应该比平均年级,比名称,id.no. 最后,它应该返回排在队列中的名字。 其余的名字都很好,但是他们的顺序不是。 输入(名称,等级avg,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

预期产出:

Dan
Ashley
Shafaet
Maria

我的结果:

Dan
Ashley
Maria
Shafaet

你能帮我找到问题吗? 先谢谢你!

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

你的Comparator是正确的。 问题在于你很可能使用Iterator遍历列表。 PriorityQueue文档指出:

方法iterator()中提供的Iterator不保证以任何特定顺序遍历优先级队列的元素。

如果你要像这样遍历你的PriorityQueue ,你应该看到正确的结果:

while (!pq.isEmpty())
    System.out.println(pq.poll().getName());
}

我在这个答案的最后加入了一个例子来充分展示。


如果你不想清除你的PriorityQueue ,你可以做几件事。 就个人而言,我不会推荐这两种方法,因为PriorityQueue的初始选择对于用例来说是不正确的,因为它们不打算重复使用。

您可以将您的PriorityQueue复制到数组中,使用Comparator实现对它们进行排序,遍历排序后的数组,例如:

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

或者在轮询时将它们添加到某种Collection ,然后将它们添加回PriorityQueue ,例如:

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

使用您的数据来演示的示例:

主要

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

}

学生 (改名,应该是单数)

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 (与问题无关的逻辑)

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

输出 (至少对我来说,第一个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

从Java 8开始,您可以使用以下代码替换整个Comparator类:

Comparator.comparingDouble(Students::getCgpa)
    .thenComparing(Students::getName)
    .thenComparingInt(Students::getId)

如果您使用的是较早版本的Java,或者坚持保留显式比较器,则必须为相同的值返回零。 您还必须编写比较器,以便它与等号一致。 从文档:

当且仅当c.compare(e1, e2)==0与每个e1 e1.equals(e2)具有相同的布尔值时,由比较器c施加在一组元素S上的顺序被称为与等于一致和S e2

当使用比较器能够强加与equals不一致的比较器来命令一个有序集合(或排序映射)时,应该谨慎。 假设使用显式比较器c的有序集合(或有序映射)与从集合S抽取的元素(或键)一起使用。 如果Sc施加的顺序与equals不一致,则排序后的集合(或排序后的映射)将表现得“奇怪”。 特别是,排序后的集合(或排序后的映射)将违反集合(或映射)的一般合约,集合(或映射)以equals定义。

(简而言之,如果两个对象相等,则比较器比较它们时必须返回零)。

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

这假设你的Students类有一个匹配的equals方法:

@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;
}
链接地址: http://www.djcxy.com/p/40735.html

上一篇: Java PriorityQueue with custom Comparator

下一篇: ngFacebook not working with phonegap