【问题标题】:Trouble with Sorting Algorithm of PriorityQueue(Java): Why is ordering different than a sorted ArrayList? [duplicate]PriorityQueue(Java) 的排序算法的问题:为什么排序与排序的 ArrayList 不同? [复制]
【发布时间】:2014-01-04 03:15:21
【问题描述】:

我正在研究霍夫曼。但是我发现 PriorityQueue 的排序算法有问题;它没有足够的比较!然后我只是写了一个简单的类来测试Collections的排序和PriorityQueue的排序:

public class Student implements Comparable<Student>{

    String name;
    int score;
    int math;

    public Student(int score, int math, String name) {
       this.name = name;
       this.score = score;
       this.math = math;
    }

    public int compareTo(Student other) {
       if (this.score > other.score) {
           return -1;
       } else if (this.score < other.score) {
           return 1;
       } else {
           if (this.math > other.math) {
               return -1;
           } else {
               return 1;
           }
       }

       return 0;
   }

   public String toString() {
       return("[" + name + " has Score: " + score + "(Math: " + math + ")]");
   }
}

但我得到了这样的结果(在控制台上):

Priority Queue::::::::::
[Jeremy Lin has Score: 2350(Math: 800)]
[Qian has Score: 2150(Math: 800)]
[PoorMath has Score: 2060(Math: 600)]
[Hui has Score: 1800(Math: 690)]
[Kaiyu has Score: 2060(Math: 800)]
[Chao has Score: 0(Math: 0)]

ArrayList sorted::::::::
[Jeremy Lin has Score: 2350(Math: 800)]
[Qian has Score: 2150(Math: 800)]
[Kaiyu has Score: 2060(Math: 800)]
[PoorMath has Score: 2060(Math: 600)]
[Hui has Score: 1800(Math: 690)]
[Chao has Score: 0(Math: 0)]

如何解释?太诡异了!

非常感谢!!

【问题讨论】:

  • 你的 compareTo() 方法永远不会返回零。
  • 你可以使用Integer.compare(int x, int y)
  • 提供您的测试方法。我的猜测是您正在迭代 PriorityQueue,它不保证以任何特定顺序进行迭代:此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选方法。方法 iterator() 中提供的 Iterator 不能保证以任何特定顺序遍历优先级队列的元素。如果您需要有序遍历,请考虑使用 Arrays.sort(pq.toArray())。 (来自docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html
  • 我试过了,我通过使用poll 方法得到了按顺序显示的结果,该方法从队列中删除了“最小”元素并返回它。

标签: java algorithm sorting arraylist priority-queue


【解决方案1】:

我认为您可能对优先级队列的工作方式有一点误解......

PriorityQueue 结构不保证整个结构按任何特定顺序排序。它只保证您从其顶部弹出的下一个元素将是最高优先级的项目。如果您查看 PriorityQueue 的 API,它不允许随机访问 PriorityQueue 中的任何元素,它只允许访问下一个元素(很像 Stack 或 Queue 结构)。

另一方面,ArrayList 是一种允许随机访问的数据结构,因此当您对其进行排序时,所有内部元素都是有序的。

因此,在您的示例中,结构都是正确的,因为它们都将 Jeremy Lin 显示为第一个条目。

如果您对 PriorityQueue 执行了类似操作,您应该会看到与排序后的 ArrayList 相同的顺序:

PriorityQueue<Student> pq;

//initialize PriorityQueue

while(pq.size() > 0)
{
   System.out.println(pq.poll());
}

我相信 Java 的 PriorityQueue 是基于标准堆数据结构的。你可以在这里找到一些基本的细节:http://en.wikipedia.org/wiki/Heap_(data_structure)

【讨论】:

  • “PriorityQueue 结构不保证整个结构按任何特定顺序排序”。好吧,它们是按优先级排序的。引用文档:“优先级队列的元素根据它们的自然顺序排序,或者由队列构建时提供的比较器排序”。毕竟这是一堆。
  • @user2336315 它们在内部存储方式中没有按优先级排序。优先级队列基于最小堆,并且有许多不同的方法可以在最小堆中布置元素,这些方法仍然会表现出正确的优先级队列行为。没有一个正确的元素顺序。所有可以保证的是所有元素都遵循Min Heap Property,即堆中的每个元素(可以看作是几乎完整的二叉树)都小于它的两个子元素。上面显示的 PriorityQueue 有许多不同的顺序仍然有效。
  • @user2336315 您仍然必须使用正确的方法来获得订单。该文档明确表示迭代器不会这样做。
  • @BrentNash 谢谢我明白你的意思:)。抱歉,现在想起来了。你能找到它提到它基于最小堆的地方吗?如果您使用优先级队列来存储每个示例的整数,并使用反向比较器(即反向自然排序),那不是最大堆吗?
  • @BrentNash 一个小问题 - 由于堆允许重复,堆属性是子树的根小于或等于子树中的最小值,而不仅仅是严格地更小。不过,很好地解释了有效堆的非唯一性!
【解决方案2】:

PriorityQueue 不是排序集合,它是一个有效维护“最低”元素的集合。来自javadoc

这个队列的头是相对于 指定的顺序。如果多个元素被捆绑为最小值,则 head 是这些元素之一 - 关系被任意打破。这 队列检索操作 poll、remove、peek 和元素访问 队列头部的元素。

方法 iterator() 中提供的迭代器保证 以任何特定顺序遍历优先级队列的元素。 如果您需要有序遍历,请考虑使用 Arrays.sort(pq.toArray())。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多