为什么这个比较器没有正确地分离奇数和偶数

时间:2017-03-23 20:55:13

标签: java sorting comparator comparable

以下是我在数组中隔离奇数和偶数的尝试(失败并成功)。预期的输出是在数组中奇数之前的所有偶数。所以,有效的输出是

<div class="select">
  <select class="form-control" id="state-dropdown">
	<option>Select State</option>
  </select>
</div>

评论中的那个版本是不起作用的版本,另一个版本有效。

在失败的版本中,我想知道为什么它不起作用。我正在做的是,如果第一个数字是奇数,第二个数字是偶数,我交换它。在所有其他情况下,我不做任何交换,这是可以的,因为如果两个数字都是偶数,或者两个数字都是奇数,或者如果已经偶数在奇数之前,则不需要交换,在这种情况下,它已经保持了预期产出的模式。

2 4 6 8 10 9 7 5 3 1 

你能帮助我理解为什么被注释的逻辑没有按预期工作吗?

2 个答案:

答案 0 :(得分:3)

您注释的代码的根本问题在于您打破了所有比较实现的预期一致性条件:

  

实现者必须确保所有x和y的sgn(x.compareTo(y))== -sgn(y.compareTo(x))。

来自http://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#compareTo-T-,但同一种语言位于Comparator。 (该部分还有另外两个类似的条件,你也应该阅读和理解)。

在你的情况下3比较2 = 1和2比较3 = 0.这使得你的实现打破了Java中所有排序算法的假定前提条件,因此它不起作用。

这一点很重要的原因在于,否则最终的顺序将取决于形成比较的每一面所发生的元素。如果算法碰巧比较2到3而不是3比2,那么你会以不同的顺序结束。文档坚持通过交换边返回完全否定的结果,以便所有实现可以是任意关于哪些元素构成比较中的第一个和第二个参数。这允许效率(并且,作为旁边,匹配比较的数学定义)。

我还注意到,在您的问题中,您暗示实施比较旨在表示在排序操作中要交换的内容和不交换的内容。这根本不是真的。有许多不同的排序算法,其中许多不交换任何东西 - 它们复制或拆分并重新加入或使用许多其他技术。或者比较可以是找到最大或最小的元素。

因此,当您定义比较时,您没有指明要交换的内容;而是你要定义什么是更小的和更大的(在这个比较中)并留下它如何用于你正在调用的算法的细节。您永远不应该假设您知道该算法是如何工作的(特别是当它将从JVM更改为JVM并从版本更改为版本时)。只需遵循文档中的条件,无论算法如何变化,都可以保证其正常工作。

顺便说一句,你可以用单一陈述来实现你的结果:

sort(a, comparingInt(n -> floorMod(n, 2));

这只是将每个数字转换为0或1,具体取决于它是偶数还是奇数,然后将它们进行比较。它使用Math.floorMod,以便它可以正确处理负数(您的实现不会)。

答案 1 :(得分:0)

比较函数用于确定哪个数字更大。你必须使任何奇数评估为更大。

import java.util.Arrays;
import java.util.Comparator;

public class Main {

    public static void main(String[] args) {
        Integer[] a = {4, 3, 1, 2, 5, 6, 8, 9, 7, 10};
//        Integer[] a = {3,4};

        Arrays.sort(a, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1%2 == o2%2) {
                    // Both numbers are odd or both numbers are even
                    return 0;
                }
                // One is odd, the other one is even
                if (o1%2 == 0) {
                    return -1;
                }
                return 1;
            }
        });
        for(int x:a) {
            System.out.print(x);
        }
    }
}