Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中具有相同值但不同标识的元素的排序列表_Java_Sorting_Arraylist - Fatal编程技术网

Java中具有相同值但不同标识的元素的排序列表

Java中具有相同值但不同标识的元素的排序列表,java,sorting,arraylist,Java,Sorting,Arraylist,我知道有几十个类似的问题,但我找不到具体问题的答案。对不起,如果我错过了它-请告诉我在哪里看,如果它存在 这个问题对我来说似乎很常见:我需要一个对象列表,该列表按对象的某些属性排序,并且每个对象在列表中只有一次。具体地说,我正在实现一个*路径查找,需要按节点的F值排序的开放列表 我尝试使用一个树集和一个比较器来比较两个节点的f值,如下所示: public class NodeFComparator implements Comparator<Node> { @Overrid

我知道有几十个类似的问题,但我找不到具体问题的答案。对不起,如果我错过了它-请告诉我在哪里看,如果它存在

这个问题对我来说似乎很常见:我需要一个对象列表,该列表按对象的某些属性排序,并且每个对象在列表中只有一次。具体地说,我正在实现一个*路径查找,需要按节点的F值排序的开放列表

我尝试使用一个树集和一个比较器来比较两个节点的f值,如下所示:

public class NodeFComparator implements Comparator<Node> {

    @Override
    public int compare(Node arg0, Node arg1) {
        return (arg0.getF() - arg1.getF());
    }

}
这个解决方案的问题似乎是,如果两个不同的节点具有相同的f值(这种情况一直发生),换句话说,比较器返回0,树集似乎将其视为Node1==Node2,并且没有将第二个节点添加到列表中,或者做一些其他奇怪的事情,因为我的openlist遗漏了应该存在的节点

因此,我能想到的对现有类执行此操作的唯一方法是使用一个简单的ArrayList,并在每次向其附加节点时对其进行排序

Java或Apache Commons中是否真的没有这样的集合类:

  • 按对象的任何属性保留对象的排序列表
  • 具有快速的查找和插入时间
  • 是否与其他集合类一样易于使用

我很困惑。

你说得对,你可以使用ArrayList而不是TreeSet,因为它不会删除重复的项(根据你传递给它的比较器)

您可以将节点添加到ArrayList,并在准备对其进行排序时,从Collections类调用该方法


Collections.sort(myList,myComparator)
只需稍微更改一下比较器:

public class NodeFComparator implements Comparator<Node> {
    @Override
    public int compare(Node arg0, Node arg1) {
        int result = arg0.getF() - arg1.getF();
        if (result == 0)
            return arg0.hashCode() - arg1.hashCode();
        return result;
    }
}
公共类NodeFComparator实现Comparator{
@凌驾
公共整数比较(节点arg0、节点arg1){
int result=arg0.getF()-arg1.getF();
如果(结果==0)
返回arg0.hashCode()-arg1.hashCode();
返回结果;
}
}

这将为具有不同f值的节点返回正确的结果,并且当节点具有相同的f值时,将通过其哈希代码对其进行比较。您可以使用除哈希代码之外的任何其他唯一属性,但我选择哈希代码是因为它们几乎是唯一的,并且每个对象都有它们。

如果希望元素比较相等(在本例中,具有相同的f值),请不要使用集合。A*算法通常是针对优先级队列定义的,从Java 5开始,Java collections API中提供了
PriorityQueue
实现:

import java.util.PriorityQueue;

. . .

PriorityQueue nodes = new PriorityQueue<Node>(new NodeFComparator());
import java.util.PriorityQueue;
. . .
PriorityQueue节点=新建PriorityQueue(new NodeFComparator());

如果compare方法与equals实现不一致,则必须小心使用哪些集合类。TreeSet在这里不是一个好的选择。另一种选择是查看Guava库中的多重映射实现

什么是类节点?如果是自定义的,是否正确实现equals/hashCode契约?节点非常复杂,我在问题后面附加了一个简短的版本。如果您添加第二个比较,如果getF()与另一个getF()相等,则应该可以解决您的问题。在这里,您可以使用.toString()并将其与其他文件进行比较。如果您将节点添加到其中,则会更容易为您提供帮助。@user:听起来很简单,也很有趣。我会努力的。thx.我知道这会起作用,但每次添加节点时对愚蠢的列表进行排序似乎是一种浪费。。。如果我使用大地图,性能不会很好!?您可以在列表最终确定后对其进行排序。但使用现代CPU,只要列表长度不超过一百万条记录,就不必担心性能问题。关键是使用最适合您的目的的数据结构。如果你想要固定时间的查找,你可以使用一个HashMap,并在运行中将其转换为一个排序列表。我不同意你的说法。演出总是很重要的。如果你不在乎,软件就糟透了。有没有听说过“过早优化是万恶之源?”性能当然很重要,但正如我所说的,如果他的列表不庞大,那么它们甚至不会影响性能。一种确保的方法是在目标机器上对其进行基准测试。确保这是一个真实的问题,而不是一个虚构的问题。可能还有很多其他实际问题需要注意。@ktm:列表每次更改时都必须进行排序,因为算法总是需要访问f值最低的节点(=最有希望的节点)。你是对的,对于小地图来说没什么区别,但是如果我有一张1000*1000的地图(这在游戏中并不少见),并且有很多NPC,它会很快变得很糟糕。我只想从一开始就做好…是的,就像用户3340630建议的那样。我认为这是一条路要走。谢谢我会尝试并尽快接受你的答案!我不得不把正确答案改成大卫·康拉德。解释在他的答案下面。简言之:您的方式有时只起作用,但对于大量节点(换言之,大型映射),它是不稳定的。而且在较小的地图上,它也可能导致探路者的错误行为。我强烈建议不要使用这种技术,而是使用PriorityQueue!我会调查的,谢谢。。。但是,a*openlist不需要重复的值。对不起,具有相同f值的值,即比较相等的值。我将编辑我的答案以反映这一点。thx david。现在我明白你的意思了。。。同时,我使用了comparator hack,但我认为您的方式更优雅。下一次我将使用优先级队列。事实证明,关于PQ,您是正确的。将树映射与tbodt和user3340630建议的奇怪比较器一起使用实际上并不可行。首先,比较器通过为及物性提供不一致的值来打破其契约。但是,只有当我使用具有数千个节点的大型贴图时,才会出现这种情况
import java.util.PriorityQueue;

. . .

PriorityQueue nodes = new PriorityQueue<Node>(new NodeFComparator());