如何使TreeSet与#equ;"不一致?

时间:2014-09-24 14:12:20

标签: java equals comparator compareto treeset

我已经阅读了很多关于TreeSet,Comparable / Comparator Interfaces,equals,compareTo,compare methods的帖子,我知道API说你必须订购#34;与equals"或者可能发生奇怪的事情。

但在我的情况下,我认为这是一个相当普遍的情况,我确实需要一个TreeSet排序,这与#equ;"不一致。

假设我们正在进行某种启发式搜索,并且我们正在从根(初始)状态开始扩展(或生成)新状态。我们将新的(扩展/生成)状态放入TreeSet中,我们通常称之为打开列表。我们想使用TreeSet容器,因为我们不希望在打开的列表中出现重复的状态。

生成/扩展的每个状态都由成本函数评估,并给出一个启发式值,显示状态的质量。我们想要按此值排序的TreeSet(打开列表)。我们希望在TreeSet的顶部具有最佳状态(具有最佳成本值)。

现在问题来了。为了适应成本值的排序,我们需要为TreeSet提供一个比较成本值的比较器。但是,两个不同的状态可以具有相同的成本/启发式值。我希望在我的公开名单上都有这两种状态,因为它们不等于#34;。但比较器需要从比较方法返回0,因为它们具有相同的成本值。因此,具有相同成本值的不同状态将不会插入到列表中。

我想举一个简单的例子来说明这一点更容易理解。 假设我们的状态是显示二进制数据的字符串,而成本函数计算字符串中的" 1" s。

让我们说这些是生成的状态及其各自的成本值。

  No  State       Cost 
  1   01001001     3
  2   01101001     4
  3   10001001     3
  4   01001111     5

正如您所看到的,这四种状态都不同。他们不等于"。但即使状态1和状态-3不同,它们也具有相同的成本值" 3"。因此,当我们按成本订购TreeSet时,state-3将不会添加到TreeSet中,因为已经存在具有相同成本值的元素。但我们需要将该状态添加到列表中,因为它是完全有效的,不同的新状态。

我该如何克服这个问题?

感谢。

2 个答案:

答案 0 :(得分:4)

你需要的只是一个做两件事的比较器:

  1. 首先比较成本。降低成本将排在第一位。
  2. 如果成本相等(并且只有那时),它会使用任意的平局判断器对状态进行排名。 (例如,比较状态的ID。)重要的是,虽然tie tie可以是任意的,但它应该是确定性的,只取决于状态对象中的字段,它将在集合中对象的整个生命周期内保持不变。
  3. 这是一种lexicographic ordering,它与equals()完全一致。 (因为如果equals()返回true,比较器将返回0。)

    完全抛弃:根据您的具体使用情况,使用PriorityQueue而不是TreeSet可能会更好。然后,您不必担心具有相同优先级的多个元素。

答案 1 :(得分:1)

“与equals一致”的含义仅表示对于彼此相等的两个对象,比较器应返回0,或者:

obj1.equals(obj2)应与comparator.compare(obj1, obj2) == 0;

的布尔值相同

但是你可以自由地使用自己的比较器,只要比较器为相同的状态返回0,就可以在高成本之前降低成本。