Java Comparator:违反总承包

时间:2013-12-03 14:59:56

标签: java

所以我有这个比较器:

import java.util.Comparator;

public class SolutionComparator implements Comparator<ExpressionTree> {
    private final int target;

    public SolutionComparator(int target) {
        this.target = target;
    }

    @Override
    public int compare(ExpressionTree o1, ExpressionTree o2) {
        int v1 = o1.getValue();
        int v2 = o2.getValue();
        if (v1 == -1 && v2 == -1)
            return 0;
        else if (v1 == -1)
            return 1;
        else if (v2 == -1)
            return -1;
        else if (v1 == v2)
            return (int)Math.signum(solutionCost(o1) - solutionCost(o2));
        else
            return (int)Math.signum(Math.abs(target-v1) - Math.abs(target-v2));
    }

    private int solutionCost(ExpressionTree v) {
        int cost = 0;
        Operation o = v.getOperator();
        if (o != Operation.NONE) {
            cost += o.getCost();
            for (ExpressionTree e : v.getChildren())
                cost += solutionCost(e);
        }
        return cost;
    }
}

我几个月来一直在查看这段代码,而且我无法找出它违反比较器一般合同的原因。

这个想法是每个ExpressionTree可以被评估为一个结果。 (getValue()方法)。如果它返回-1,它总是高于其他数字。如果值不同,则与target的接近程度进行比较。如果值相同,则按解决方案成本进行比较。

使用此比较器,Java抛出IllegalStatesException。但是,如果我删除基于成本的比较,它就会起作用。


编辑:异常跟踪

Exception in thread "Thread-3" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeHi(TimSort.java:868)
    at java.util.TimSort.mergeAt(TimSort.java:485)
    at java.util.TimSort.mergeCollapse(TimSort.java:408)
    at java.util.TimSort.sort(TimSort.java:214)
    at java.util.TimSort.sort(TimSort.java:173)
    at java.util.Arrays.sort(Arrays.java:659)
    at java.util.Collections.sort(Collections.java:217)
    at ***.run(***:123)
    at java.lang.Thread.run(Thread.java:722)

1 个答案:

答案 0 :(得分:10)

您的Comparator违反了the contract所要求的平等传递性:

  

最后,实现者必须确保compare(x,y)== 0意味着所有z的sgn(compare(x,z))== sgn(compare(y,z))。

假设您有三个ExpressionTreeo1, o2, o3,各自的值为
v1, v2, v3
和解决方案成本
s1, s2, s3
这样的 v1 == v2
target - v1 == v3 - target(所以abs(target-v1) == abs(target-v3)

s1 < s2(以便compare(o1, o2) == -1,为简单起见可以说o1 < o2 然后是o1 == o3o2 == o3,但o1 < o2,即 compare(o1, o3) == 0

sgn(compare(o1, o2)) != sgn(compare(o3, o2))
因为
sgn(compare(o1, o2)) == -1sgn(compare(o3, o2)) == 0

我不知道你会如何解决这个问题,但这就是它的原因。

编辑 @Nat(OP)提出了这个优雅的解决方案:

  

修复是替换
  if (v1 == v2)
  与
  if (Math.abs(target-v1) == Math.abs(target-v2))