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

时间:2014-02-27 18:22:00

标签: java sorting arraylist

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

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

我尝试使用带有比较器的TreeSet,比较两个节点的f值,如下所示:

public class NodeFComparator implements Comparator<Node> {

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

}

Class Node看起来像这样:

public class Node {

    PathableMap parentmap;
    Point coord;    // coordinates on the map
    private Node parent;    // parent node: used by astar to backtrace shortest path

    (etc etc)

    /*
     * F-value of a node is the sum of the distance from start + distance to target.
     * The nodes are searched in the order of that value.
     */
    public int getF() {
        return getG() + getH();
    }

    @Override
    public int hashCode() {
        final int prime = 65537;
        return prime * coord.x + coord.y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Node other = (Node) obj;
        if (coord == null) {
            if (other.coord != null)
                return false;
        } else if (!coord.equals(other.coord))
            return false;
        return true;
    }

}

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

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

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

  • 通过对象的任何属性保留对象的排序列表
  • 具有快速查找和插入时间
  • 和其他集合类一样容易使用吗?
我很困惑。

4 个答案:

答案 0 :(得分:3)

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

import java.util.PriorityQueue;

. . .

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

答案 1 :(得分:2)

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

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

Collections.sort(myList, myComparator)

答案 2 :(得分:2)

稍微改变你的比较器:

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;
    }
}

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

答案 3 :(得分:0)

如果compare方法与equals实现不一致,那么您必须小心使用哪些集合类。 TreeSet在这里不是一个好选择。另一种方法是查看Guava库https://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap

中的Multimap实现