【问题标题】:What is wrong with my comparable interface logic?我的类似界面逻辑有什么问题?
【发布时间】:2020-09-09 09:56:10
【问题描述】:

所以问题如下

每个进入队列的学生都会分配一个唯一的 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 的确切顺序复制到列表中。

【问题讨论】:

  • 请说明订单有什么问题。

标签: java data-structures priority-queue comparable


【解决方案1】:

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

在这种情况下,它可能看起来像:

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

【讨论】:

  • 这与我所做的类似。我不确定我的逻辑的哪一部分出错了
  • @Fenzox 你的代码有if ( this.getCgpa() == other.getCgpa()) return this.getName().compareTo(other.getName()); 之前你告诉它检查this.getName().compareTo(other.getName()) == 0
  • @khelwood 该方法在返回后不会停止检查吗?
  • @Fenzox 是的,如果没有比较getId() 的位,它会返回零。这就是问题所在。
  • @khelwood 我根据你的建议更新了我的代码,但仍然得到相同的输出
【解决方案2】:

问题在于 PriorityQueue 的迭代器无法保证其排序语义(除此之外,请注意 PriorityQueue 不是列表!)

引用java doc(强调我的):

这个类和它的迭代器实现了所有的 集合的可选方法和 迭代器接口。方法中提供的迭代器 iterator() 保证遍历 任何特定顺序的优先级队列。如果您需要订购 遍历,考虑使用 Arrays.sort(pq.toArray())。

这意味着除非您使用队列语义(例如 addpollremoveoffer... 等),否则您将无法获得比较器的排序。

查看实现,调用new ArrayList&lt;Students&gt;(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 更具可读性(并且避免重复)。

【讨论】:

  • 您是说使用 ArrayList(pq) 不会将 pq 中的值顺序完全复制到列表中吗?我用 List studentList = new ArrayList(); while(!pq.isEmpty()) { studentList.add(pq.poll()); }。这对我有用
  • 我是说 new ArrayList(pq) 在队列上使用了一个迭代器,并且队列的迭代器不反映比较器的顺序。这意味着生成的 ArrayList 可能会或可能不会根据比较器进行排序。当使用队列语义(poll 是队列的一种方法)时,您确实会按照比较器的顺序获取元素。
猜你喜欢
  • 2016-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多