Java:PriorityQueue 从自定义比较器返回不正确的顺序? [复制]

Posted

技术标签:

【中文标题】Java:PriorityQueue 从自定义比较器返回不正确的顺序? [复制]【英文标题】:Java: PriorityQueue returning incorrect ordering from custom comparator? [duplicate] 【发布时间】:2010-06-15 19:50:46 【问题描述】:

我编写了一个自定义比较器来比较我的节点类,但是 java 优先级队列没有以正确的顺序返回我的项目。

这是我的比较器:

public int compare(Node n1, Node n2)

    if (n1.getF() > n2.getF())
        return +1;
    
    else if (n1.getF() < n2.getF())
        return -1;
    
    else   // equal
        return 0;
    

其中 getF 返回一个双精度值。然而,在将几个节点插入优先级队列后,我使用以下命令将它们打印出来:

while(open.size() > 0) 
    Node t = (Node)(open.remove());
    System.out.println(t.getF());

结果:

6.830951894845301
6.830951894845301
6.0
6.0
5.242640687119285
7.4031242374328485
7.4031242374328485
8.071067811865476

任何想法为什么会这样?我的比较器错了吗?谢谢。

迈克

【问题讨论】:

您的“Java 优先级队列”是什么实际的 Java 类(我假设是 PriorityQueue),您是如何构建它的? java.util.PriorityQueue,我猜? 没有回答您的问题,但我注意到您可以将比较器简化为:return Double.compare(n1.getF(), n2.getF()); @Gray - 这就是我声明它的方式: Comparator 比较器 = new NodeComparator(); PriorityQueue open = new PriorityQueue(INITIAL_SIZE,comparator); 有点明显,但是,您不是处于多线程环境中吗?打印数据时没有另一个线程写入数据? 【参考方案1】:

您如何打印出这些值?我不认为来自PriorityQueue 的迭代器提供了与整个类相同的排序保证,如果你正在这样做,那么可能

for(Node n : queue) 
System.out.println(n.getF());

你会得到无序的输出。订购保证仅适用于offertakepollpeek,可能还有其他一些方法。

javadocs 中特别提到了优先级队列 @9​​87654321@ 的迭代器

【讨论】:

没错;来自PriorityQueue javadoc 的iterator() 方法:“迭代器不会以任何特定顺序返回元素。” “你是如何打印出这些值的?”......问题是“我用......打印出来”。 我没有使用迭代器。 Comparator 比较器 = new NodeComparator(); PriorityQueue open = new PriorityQueue(INITIAL_SIZE, 比较器);然后是上面的while循环。【参考方案2】:

不知道你的代码有什么问题,但这对我有用:

import java.util.*;
public class Test 
    public static void main(String[] args) 
        PriorityQueue<Node> open = new PriorityQueue<Node>(10,
                new Comparator<Node>() 
            @Override
            public int compare(Node n1, Node n2)
                if (n1.getF() > n2.getF())
                    return +1;
                
                else if (n1.getF() < n2.getF())
                    return -1;
                
                else   // equal
                    return 0;
                
            
        );

        for (int i = 0; i < 20; i++)
            open.add(new Node());

        while(open.size() > 0) 
            Node t = (Node)(open.remove());
            System.out.println(t.getF());
        
    


class Node 
    double d = Math.random() * 10;
    public double getF()  return d; 

输出:

0.21442281608773262
1.9965384843480016
2.6660026888929824
2.888889937975976
3.098932914222398
3.1059072964534638
4.193212975907516
4.296282412431935
4.3241392173963735
4.825876226139123
5.193550353435191
5.637831708672641
5.949759449054407
6.620639629878806
7.505126870725806
7.966337123623846
8.270840212631589
8.484502118941545
8.730910327480023
9.191324325662219

确保 getF() 不会意外返回双精度的 int 版本。


更新:您不能更新定义插入后元素顺序的数据。在这种情况下,您需要提取元素、更新它并重新插入它。

【讨论】:

你可以尝试使用类迭代器吗?看看你是否得到无序输出? 那么它的排序不正确。说得通。如果它被实现为一个堆,它所知道的就是下一个要删除的元素是。 嗯...我先将节点添加到prio队列中,然后使用节点的“setF”函数更改f值。插入对象后,prio 队列中的值是否没有更新?即使我指向优先队列中的节点? @Ceilingfish - 我的节点类将 f 值初始化为 -1,然后插入 prio 队列,然后更新 f val。这与您上面的示例不同。感谢您仔细检查基本逻辑,谢谢。 PriorityQueue 将数据插入到正确的位置。数据在被轮询之前不会被使用。如果您在插入后更改数据,则不会对其进行排序。 Jacob,您可能应该将此评论转化为答案,这样您就可以得到赞誉(当然,查看问题的人也知道在哪里可以找到答案)

以上是关于Java:PriorityQueue 从自定义比较器返回不正确的顺序? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java的优先队列PriorityQueue详解

Java 中的比较器和 PriorityQueue 是如何工作的?

是否有具有固定容量和自定义比较器的 PriorityQueue 实现?

Java中的Collection和Map--PriorityQueue

从自定义比较器(实现RawComparator接口的方式)总结的经验

将 Java PriorityQueue 更改为 Max PQ [重复]