TreeSet add()返回false

时间:2013-05-16 17:04:42

标签: java treeset

我正在Java中实现一个A *算法,我使用TreeSet作为保持打开列表排序的简单方法。如果你不熟悉A *,那么它基本上是一个从A到B获得最短路径的函数,而开放列表是根据它们与B的接近度排序的节点列表(在我的例子中是Tiles)。

我的对象实现了compareTo()函数的排序,如下所示:

@Override
public int compareTo( Tile b ) 
{
    return ( this.f< b.f) ? -1 : ( this.f> b.f) ? 1 : 0;
}

当我尝试将一些切片添加到打开列表时,我的问题出现了 - TreeSet似乎使用compareTo()来检查对象是否已经存在,而不是equals()。由于两个不同的Tiles可能具有相同的f值,因此TreeSet认为该对象已存在于列表中并且不会添加它。

根据文档(或至少我如何阅读),它应该使用equals

“如果指定的元素不存在,则将其添加到此集合。更正式地,如果集合中不包含元素e2,则将指定的元素e添加到此集合中,以便(e == null?e2 == null:e.equals(e2))。“ (强调我的)。

如何在调用equals()add()contains()进行排序时让TreeSet使用compareTo()?有关信息,我的Tile类不会覆盖equals()函数,因此它应该是默认的return a == b

如果使用TreeSet无法实现我的目标,那么我应该使用的正确集合是什么?

3 个答案:

答案 0 :(得分:6)

这是预期的行为,根据TreeSet文档:

  

请注意,如果要正确实现Set接口,则由set维护的排序(无论是否提供显式比较器)必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,通过这种方法被认为相等的元素是相等的。集合的行为即使其排序与equals不一致也是明确定义的;它只是没有遵守Set接口的一般合同。

在致电TreeSetequals时,您无法让add使用contains。您最好的选择是通过compareTo属性以及equals关注的其他任何属性来使f方法与equals保持一致。

答案 1 :(得分:0)

我希望以下示例可以帮助SO用户。我有类似的情况,我处理的方式是除了价值之外还使用id。就我而言,价值指的是一个频率。

请注意使用'paddedText' - 如果你进行字符串比较,这是很重要的其他3> 11。

public int compareTo(Object o) {
		String oText= o.getValue()+"";
		oText = String.format("%20s",oText).replace(' ', '0')+o.getName();
		paddedText = this.value +""; 
		paddedText=String.format("%20s",paddedText).replace(' ', '0') + this.name;
	        return oText.compareTo(paddedText);
	}

答案 2 :(得分:0)

这里的答案已经让我创造了这个。我会留在这里,因为似乎只有解决方案的要点。

    @Override
    public int compare(TileState lhs, TileState rhs) {
        int compare = (lhs.getTaxicab + lhs.mMoves.size())
                - (rhs.getTaxicab + rhs.mMoves.size());
        if (compare == 0 && !lhs.equals(rhs)) return 1;
        return compare;
    }

比较方法返回0时,您只需要担心。

如果是这种情况并且equals将返回false,则返回0以外的任何内容。