简体   繁体   English

Java - 列表 <Integer> 排序,比较和溢出

[英]Java - List<Integer> sort, comparator and overflow

I've the following code that sorts a list in a descending order 我有以下代码按降序对列表进行排序

List<Integer> list=Arrays.asList(Integer.MAX_VALUE, -1);
list.sort((x, y) -> y-x);
System.out.println(list)

The result is 结果是

[-1, 2147483647]

Now, I know that I should not write yx because it can cause overflow problem. 现在,我知道我不应该写yx因为它可能导致溢出问题。

But the question is why is the output that? 但问题是为什么输出呢? I believed the output would be [2147483647, -1] because -1 - Integer.MAX_VALUE is -2147483648 , still a negative integer, ad the operation seems not be affected by overflow problem. 我相信输出将是[2147483647, -1]因为-1 - Integer.MAX_VALUE-2147483648 ,仍然是负整数,广告操作似乎不受溢出问题的影响。 What I did wrong? 我做错了什么?

As you can read in Oracle's Object Ordening Java Tutorial near the bottom of the page: 您可以在页面底部附近的Oracle的Object Ordening Java Tutorial中阅读:

You might be tempted to replace the final return statement in the Comparator with the simpler: 您可能想要使用更简单的方法替换Comparator中的最终return语句:

 return e1.number() - e2.number(); 

Don't do it unless you're absolutely sure no one will ever have a negative employee number! 除非你绝对确定没有人会有负面的员工编号,否则不要这样做! This trick does not work in general because the signed integer type is not big enough to represent the difference of two arbitrary signed integers. 这个技巧一般不起作用,因为有符号整数类型不足以表示两个任意有符号整数的差异。 If i is a large positive integer and j is a large negative integer, i - j will overflow and will return a negative integer. 如果i是一个大的正整数且j是一个大的负整数,i-j将溢出并返回一个负整数。 The resulting comparator violates one of the four technical restrictions we keep talking about (transitivity) and produces horrible, subtle bugs. 由此产生的比较器违反了我们一直在讨论的四个技术限制之一(传递性)并产生可怕的,微妙的错误。 This is not a purely theoretical concern; 这不是纯粹的理论问题; people get burned by it. 人们被它烧了。

The situation described here is what the OP encounters: the difference between the two integers is more than Integer.MAX_VALUE and will therefore overflow during comparison, resulting in an unexpected sorting. 这里描述的情况是OP遇到的情况:两个整数之间的差异大于Integer.MAX_VALUE ,因此在比较期间会溢出,从而导致意外排序。

I just did what exactly @Robin Topper told. 我只是做了@Robin Topper所说的。

import java.util.*;
public class Test {
    public static void main(String... args) {
        List<Integer> list = Arrays.asList(Integer.MAX_VALUE, -1);
        list.sort((x, y) -> {
            System.out.println("x: " + x + " y: " + y);
            System.out.println("y - x = " + (y - x));
            return y - x;
        });
        System.out.println(list);
    }
}

And I got 我得到了

x: -1 y: 2147483647
y - x = -2147483648
[-1, 2147483647]

And we can see that 我们可以看到

\n

List#sort(Comparator) applies values onto given Comparator in inverse order . List#sort(Comparator)以相反的顺序将值应用于给定的 Comparator

  1. With a given Comparator , 使用给定的Comparator
  2. When it's applies with -1 and 2147483647 , 当它适用于-12147483647
  3. The (y - x) part ( 2147483647 - -1 ) overflowed as -2147483648 which is negative, (y - x)部分( 2147483647 - -1 )溢出为-2147483648 ,为负数,
  4. And it is true that -1 is less than 2147483647 . 而且-1确实小于2147483647

Here's the sourcecodes. 这是源代码。

List#sort(Comparator) 清单#排序(比较)

@SuppressWarnings({"unchecked", "rawtypes"})
default void More ...sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
         i.set((E) e);
    }
}

Arrays#sort(Comparator) 数组排序#(比较)

public static void sort(int[] a) {
    DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}

DualPovotQuicksort#sort() DualPovotQuicksort#排序()

Before we start you need to know that Comparator considers pair (x,y) as ordered according to its design if compare(x,y) < 0 在我们开始之前,你需要知道,如果compare(x,y) < 0根据其设计compare(x,y) < 0 pair(x,y)视为有序的
(just like for natural (ascending) order: if x<y then xy<0 ). (就像自然(升序)顺序一样:如果x<yxy<0 )。


Integer overflow 整数溢出

In mathematical world, if x and y in pair (x,y) are in ascending order we can write it as x<y which can also be rewritten as xy<0 . 在数学世界中,如果对(x,y)中的x和y按升序排列,我们可以将其写为x<y ,也可以将其重写为xy<0 Descending order can be represented as x>y which can be rewritten as xy>0 . 降序可以表示为x>y ,可以将其重写为xy>0
But such rewriting is possible only in mathematical world. 但这种重写只有在数学世界中才有可能。 In IT world numeric types like int have their min and max values, and if we will try to calculate values out of that range we will face integer overflow . 在IT世界中,像int这样的数字类型有它们的最小值和最大值,如果我们尝试计算超出该范围的值,我们将面临整数溢出 Your example is one of that cases. 你的例子就是其中一个例子。 If x = -1 and y = 2147483647 then comparator calculating yx will return -2147483648 如果x = -1y = 2147483647那么比较器计算yx将返回-2147483648

     y       -   x
(2147483647) - (-1) = -2147483648 

instead of positive 2147483648 . 而不是积极的2147483648

Because of that, incorrect (and negative) result is returned, making sorting algorithm "think" that values of x and y are in correct order. 因此,返回不正确 (和否定)的结果,使排序算法“认为” xy正确

Wait, if that result was mistake, then how we got as result elements in ascending order [-1, 2147483647] ? 等等,如果结果是错误的,那么我们如何以升序 [-1, 2147483647]得到结果元素? Shouldn't that "incorrect" order be descending? 那个“不正确”的命令不应该下降吗?

No, because Comparator returning yx describes descending order. 不,因为比较器返回yx描述了降序 Take a look. 看一看。 Elements x and y used in any Comparator.compare(x,y) are considered to be in correct order when Comparator.compare(x,y)<0 . Comparator.compare(x,y)<0时,任何Comparator.compare(x,y)中使用的元素xy都被认为是正确的顺序。 If we use code of our comparator we will get yx<0 , in order words y<x (or simpler x>y ). 如果我们使用比较器的代码,我们将得到yx<0 ,顺序为y<x (或更简单的x>y )。

It can also be easily observed if we change a little elements in list 如果我们更改列表中的一些元素,也可以很容易地观察到它

List<Integer> list = Arrays.asList(-1, 2, 5);

where after sorting we will get 我们将在排序后得到

[5, 2, -1]

In short: 简而言之:

  • sorting algorithm uses Comparator which describes descending order 排序算法使用描述降序的 Comparator
  • but since Comparator makes mistake (caused by integer overflow) it doesn't inform sorting algorithm about need to "change order" of -1 and 2147483647 so they stay at their positions. 但由于比较器出错(由整数溢出引起),它不通知排序算法需要“改变顺序” -12147483647以便它们保持在他们的位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM