"比较方法违反了其总合同" - 我无法发现任何不及物

时间:2015-06-19 15:20:22

标签: java comparator illegalargumentexception timsort

编辑:为什么我认为这不是重复的:正如 biziclop 所写的那样,这里的问题不是不敏感(a>b & b>c => a>c),就像这里提到的其他问题一样,但是条款{{ 1}}被违反,所以它是一个不同的问题。

我收到以下错误消息:

a>b => -(b>a)

这就是它发生的地方:

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeForceCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at construct.Repair.regretRepair(Repair.java:101)
at lns.One.repaired(One.java:122)
at lns.One.segment(One.java:68)
at lns.One.lnsSolution(One.java:35)
at lns.All.lnsSolutions(All.java:22)
at barter.Genetic.initialPopulation(Genetic.java:36)
at barter.Genetic.run(Genetic.java:26)
at program.Main.main(Main.java:22)

这是定义RegretProfit对象的类:

Arrays.sort(regretProfits, new Comparator<RegretProfit>(){
            @Override
            public int compare(RegretProfit first, RegretProfit second){
                if (first.possibleRoutes <= 0){
                    if (second.possibleRoutes > 0){
                        return 1;
                    }
                    return 0;
                }                   
                if (first.possibleRoutes < solution.schedule.size() - kay + 1){
                    if (first.possibleRoutes < second.possibleRoutes){
                        return -1;
                    }
                    if (first.possibleRoutes > second.possibleRoutes){
                        return 1;
                    }
                    if (first.profit > second.profit){
                        return -1;
                    }
                    if (first.profit < second.profit){
                        return 1;
                    }
                }
                if (first.regret > second.regret){
                    return -1;
                }
                if (first.regret < second.regret){
                    return 1;
                }
                return 0;
            }
        ;});

错误仅在每几千次迭代中发生。如果有人知道问题可能是什么,我会非常感激。我已经读过,不和谐会引起这种异常,但我真的无法弄清楚我可能出错的地方。

解决了它,感谢 biziclop

public class RegretProfit {
    public int[] order;
    public double regret;
    public double profit;
    public int possibleRoutes;
}

1 个答案:

答案 0 :(得分:4)

传递性不是这里的关键问题,违反合同的部分是sgn(compare(x, y)) == -sgn(compare(y, x))

如果你有这些记录,例如:

 first.possibleRoutes = -1; first.regret = 1
 second.possibleRoutes = 1; second.regret = -1

您的比较器返回1.但如果您交换它们:

 first.possibleRoutes = 1; first.regret = -1
 second.possibleRoutes = -1; second.regret = 1

您的比较器仍可能返回1.

查看代码有两个可疑的非对称结构:

            if (first.possibleRoutes <= 0){
                if (second.possibleRoutes > 0){
                    return 1;
                }
                return 0;
            } 

如果firstsecond被撤销,那么这里没有匹配的-1返回。您还可以将possibleRoutes <= 0的所有项目视为相等,这可能不是您想要的。

            if (first.possibleRoutes < solution.schedule.size() - kay + 1){

在此输入一个纯粹基于first值的分支,这意味着此分支也可能导致sgn(compare(x, y)) != -sgn(compare(y, x))

当然有可能在整个系统的额外限制下,两个问题相互抵消(显然他们不会在这种情况下),但它是设计比较器的一种非常脆弱的方式。我建议你确保所有分支都是对称的。它可以更容易地推断出代码的正确性。