我的可比接口逻辑有什么问题?

问题描述

所以问题如下

唯一的ID被分配给每个进入队列的学生。队列根据以下条件(优先条件)为学生服务:

具有最高累积平均成绩(CGPA)的学生被送达。

所有具有相同CGPA的学生都将按姓名(区分大小写)的升序排列。

任何具有相同CGPA和姓名的学生都将按照ID的升序排列

我的代码

class Priorities{
    public List<Students> getStudents(List<String> events) {
            PriorityQueue<Students> pq = new PriorityQueue<Students>();
            for ( String s : events) {
                if ( s.contains("ENTER")) {
                    String [] arr = s.split(" ");
                    int id = Integer.parseInt(arr[3]);
                    String name = arr[1];
                    Double cgpa = Double.parseDouble(arr[2]);       
                    pq.add(new Students(id,name,cgpa));
                }
                else
                    pq.poll();
            
            }
            List<Students> studentList = new ArrayList<Students>(pq);
    
            return studentList;
        }
        
        
        
    }
    
class Students implements Comparable<Students>{
    
    int id;
    String name;
    double cgpa;
    
    public Students(int id,String name,double cgpa) {
        this.id = id;
        this.name = name;
        this.cgpa = cgpa;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getCgpa() {
        return cgpa;
    }

    public void setCgpa(double cgpa) {
        this.cgpa = cgpa;
    }
        // -1 return left,1 return right
    public int compareto(Students other) {
    if ( this.equals(other))
        return 0;
    else if ( this.getCgpa() > other.getCgpa())
        return -1;
    else if ( this.getCgpa() < other.getCgpa())
        return 1;
    else if ( this.getCgpa() == other.getCgpa() && this.getName().compareto(other.getName()) == 0)
        return Integer.compare(this.getId(),other.getId());
    else 
        return this.getName().compareto(other.getName());
    
        
}
}

样本输入

12
ENTER John 3.75 50
ENTER Mark 3.8 24
ENTER Shafaet 3.7 35
SERVED
SERVED
ENTER Samiha 3.85 36
SERVED
ENTER Ashley 3.9 42
ENTER Maria 3.6 46
ENTER Anik 3.95 49
ENTER Dan 3.95 50
SERVED

样本输出

Dan
Ashley
Shafaet
Maria

我得到以下内容

Dan
Ashley
Maria
Shafaet

编辑:使用

List<Students> studentList = new ArrayList<Students>();
        while(!pq.isEmpty())
        {
            studentList.add(pq.poll());
        }

代替List studentList = new ArrayList(pq);帮助将PQ的确切顺序复制到列表中。

解决方法

比较器的一般结构应为:比较一个字段;如果字段值不同,则返回;如果它们相同,请继续下一个字段。

在这种情况下,它可能类似于:

int cmp;

cmp = Double.compare(other.getCgpa(),this.getCgpa());
if (cmp != 0) return cmp;

cmp = this.getName().compareTo(other.getName());
if (cmp != 0) return cmp;

cmp = Integer.compare(this.getId(),other.getId());
if (cmp != 0) return cmp;

return 0;

(最后一个ifreturn可以折叠成return cmp;;但我认为,如果您像上面那样做,以后再扩展会更容易,因为您可以随后插入另一个cmp/if。)

,

问题是PriorityQueue的排序语义不能在其迭代器中得到保证(最重要的是,请注意PriorityQueue不是List!)

引用java doc(强调我的意思):

该类及其迭代器实现所有 Collection的可选方法和 迭代器接口。方法中提供的Iterator 不能保证遍历iterator()的元素 以任何特定顺序的优先级队列。如果您需要订购 遍历,请考虑使用Arrays.sort(pq.toArray())。

这意味着除非您使用队列语义(例如addpollremoveoffer等),否则您不会得到比较器的排序。

在查看实现时,调用new ArrayList<Students>(pq);(或PriorityQueue#toString())是使用迭代器实现的,因此它不考虑优先级。

这里的要点:

  • 仅在队列语义的情况下使用PriorityQueue是可以的,在迭代/随机访问的情况下不能使用
  • List和我知道的is not provided by a standard Java class的“实时”分类see also结合起来。 (您可以使用比较器对列表进行排序,但是每次添加元素时都不会对列表进行排序)。尽管有这样的集合,但是使用Set语义,请参见TreeSet,您将在链接的答案中找到它们。请注意,Set语义是不同的(它们保持其元素的唯一性,获得唯一性的含义有些棘手。例如,HashSet的唯一性由hashCode / equals定义,而TreeSet的由比较器定义)。

话虽如此,比较器的Andy's implementation更具可读性(并且避免重复)。