当前位置: 首页 > 知识库问答 >
问题:

“比较法违背了它的总契约!”一切似乎都没问题

夹谷沛
2023-03-14

我知道这里描述的Java(和一般)中的比较规则。
我有一个字符串数组列表。
每个字符串代表一个德州扑克手,忽略花色。
每个字符串正好有13个字符长。
每个字符串仅由总和为7的数字组成。

例如,“0100300200100”代表一手由一张3、三张6、两张9和一张皇后组成的扑克。< br >(在这种情况下,这手牌代表满堂红-六加九)。

我想根据扑克手的力量对这个列表进行排序
我有以下java代码,它实现了比较器的比较方法。

final Comparator<String> COMBINATION_ORDER = new Comparator<String>() {
    @Override
    public int compare(String c1, String c2) {
        if (c1.indexOf('4') != -1 || c2.indexOf('4') != -1) {  // Four of a kind
            if (c1.indexOf('4') == c2.indexOf('4')) {
                for (int i = 12; i >= 0; i--) {
                    if (c1.charAt(i) != '0' && c1.charAt(i) != '4') {
                        if (c2.charAt(i) != '0' && c2.charAt(i) != '4') {
                            return 0;
                        }
                        return 1;
                    }
                    if (c2.charAt(i) != '0' && c2.charAt(i) != '4') {
                        return -1;
                    }
                }
            }
            return c1.indexOf('4') - c2.indexOf('4');
        }
        int tripleCount1 = StringFunctions.countOccurrencesOf(c1, "3");
        int tripleCount2 = StringFunctions.countOccurrencesOf(c2, "3");
        if (tripleCount1 > 1 || (tripleCount1 == 1 && c1.indexOf('2') != -1) || tripleCount2 > 1 || (tripleCount2 == 1 && c2.indexOf('2') != -1)) {  // Full house
            int higherTriple = c1.lastIndexOf('3');
            if (higherTriple == c2.lastIndexOf('3')) {
                for (int i = 12; i >= 0; i--) {
                    if (i == higherTriple) {
                        continue;
                    }
                    if (c1.charAt(i) == '2' || c1.charAt(i) == '3') {
                        if (c2.charAt(i) == '2' || c2.charAt(i) == '3') {
                            return 0;
                        }
                        return 1;
                    }
                    if (c2.charAt(i) == '2' || c2.charAt(i) == '3') {
                        return -1;
                    }
                }
            }
            return higherTriple - c2.lastIndexOf('3');
        }
        return 0;
    }
};

与此同时,我只提到四人组和满屋子。这意味着其他每手牌都将被视为彼此平等(但不如四人或满屋)。

但是当我分类的时候:

combinations.sort(COMBINATION_ORDER);

(其中组合是我的ArrayList)。

我得到一个例外。

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(TimSort.java:773)
    at java.util.TimSort.mergeAt(TimSort.java:510)
    at java.util.TimSort.mergeCollapse(TimSort.java:437)
    at java.util.TimSort.sort(TimSort.java:241)
    at java.util.Arrays.sort(Arrays.java:1512)
    at java.util.ArrayList.sort(ArrayList.java:1454)
    at Poker.main(Poker.java:120)

请帮助我理解代码有什么问题。< br >非常感谢。

编辑:

正如@ajb所说,我没有考虑到没有满屋的“三分之一”。

解决方案:

final Comparator<String> COMBINATION_ORDER = new Comparator<String>() {
    @Override
    public int compare(String c1, String c2) {
        if (c1.indexOf('4') != -1 || c2.indexOf('4') != -1) {  // Four of a kind
            if (c1.indexOf('4') == c2.indexOf('4')) {
                for (int i = 12; i >= 0; i--) {
                    if (c1.charAt(i) != '0' && c1.charAt(i) != '4') {
                        if (c2.charAt(i) != '0' && c2.charAt(i) != '4') {
                            return 0;
                        }
                        return 1;
                    }
                    if (c2.charAt(i) != '0' && c2.charAt(i) != '4') {
                        return -1;
                    }
                }
            }
            return c1.indexOf('4') - c2.indexOf('4');
        }
        int tripleCount1 = StringFunctions.countOccurrencesOf(c1, "3");
        int tripleCount2 = StringFunctions.countOccurrencesOf(c2, "3");
        if (tripleCount1 > 1 || (tripleCount1 == 1 && c1.indexOf('2') != -1)) {      // c1 Full house
            if (tripleCount2 > 1 || (tripleCount2 == 1 && c2.indexOf('2') != -1)) {  // c2 Full house too
                int higherTriple = c1.lastIndexOf('3');
                if (higherTriple == c2.lastIndexOf('3')) {
                    for (int i = 12; i >= 0; i--) {
                        if (i == higherTriple) {
                            continue;
                        }
                        if (c1.charAt(i) == '2' || c1.charAt(i) == '3') {
                            if (c2.charAt(i) == '2' || c2.charAt(i) == '3') {
                                return 0;
                            }
                            return 1;                                                // only c1 Full house
                        }
                        if (c2.charAt(i) == '2' || c2.charAt(i) == '3') {            // only c2 Full house
                            return -1;
                        }
                    }
                }
                return higherTriple - c2.lastIndexOf('3');
            }
            return 1;
        }
        if (tripleCount2 > 1 || (tripleCount2 == 1 && c2.indexOf('2') != -1)) {
            return -1;
        }
        return 0;
    }
};

共有1个答案

龚永新
2023-03-14

比较器必须遵守的条件之一是它必须是可传递的。也就是说,如果A

您的算法中至少存在一个逻辑错误。(可能还有其他错误,但我绝对可以发现这个错误,它绝对会导致异常。问题是当一只手有一个完整的房子,而另一只手有 3 个类型但不是完整的房子时。你的代码并不总是让整个房子变得更好。如果 3 张牌比满屋中的三张牌高出三张牌,那么 3 张牌的比较会更大。所以假设一只手是KKK8743,另一只手是QQQ6632,另一只手是JJJ8743。您的代码错误地使 KKK8743

 类似资料:
  • 我制作了一个带有jPanel和JLabel数组的调色板。起初它运行良好,但后来我从 JPanel 中取出了一些其他 jLabels,并添加了一些事件。现在我不断收到此错误: 我试图删除第一次收到此错误后所做的一切,但仍然不断收到它。当我将布局从 GridLayout 更改为其他任何内容时,错误消失了,但代码变得无用。所以我需要网格布局。当我将该 JPanel 中的所有内容移动到另一个 JPanel

  • 有人能解释一下为什么我下面的比较器有时候会抛出上面的异常吗? 注意:myObject 中的 id 字段类型为 long。 解决方案: 基于@amit的回答

  • 偏离变量只是包含以下字段的对象的一个实例: 附言时间对象是来自 Joda-Time 库的 DateTime 实例,TransportType 是包含常量火车、海船、驳船和卡车的枚举。 编辑: 好的,所以我将比较器编辑为以下内容: 但这显然违反了一般契约。我如何让它按时间排序,然后根据它们的其他属性对那些具有相等时间的对象进行排序,只关心它们是否相等?希望这有意义… 编辑:解决方案 谢谢大家回答我的

  • 我有时会得到一个 for 我可以始终如一地抛出此异常,实时数据运行足够长的时间,但我不确定如何解决问题的实际原因。 我的比较仪有什么问题?(具体来说,我违反了合同的哪一部分?)如何在不掩盖异常的情况下修复它? 我使用的是 Java 7,如果不进行重大重写就无法升级。 我可以通过将设置为来掩盖异常,但这不是一个理想的解决方案。 我尝试创建测试来随机生成数据并验证每个合同条件。我无法抛出异常。 我尝试

  • 我在整理名单 排序代码: FinalSentence类标头: compareTo()实现: 这是例外: 对于一个小列表(少于 50 个元素),它可以工作。对于一个大型列表(它也应该与那些一起使用),它会引发此异常。列表的实例类型是 ArrayList,这并不重要。 我不知道如何深入了解这一点。列表已满,元素类型相同(那里没有多态性),但是对于大型列表,我得到了这个奇怪的例外。 有什么想法吗? 谢谢

  • 我有一个自己的,相对复杂的字符串比较器和一个庞大的字符串列表(~100个字符串,已经尝试减少,但问题不可重现),其中对它们进行排序会产生上述错误尝试使用Java 7排序。我想,规则 可能会被侵犯。找出违反合同的样品的最好方法是什么?