簡體   English   中英

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

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

我有以下代碼按降序對列表進行排序

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

結果是

[-1, 2147483647]

現在,我知道我不應該寫yx因為它可能導致溢出問題。

但問題是為什么輸出呢? 我相信輸出將是[2147483647, -1]因為-1 - Integer.MAX_VALUE-2147483648 ,仍然是負整數,廣告操作似乎不受溢出問題的影響。 我做錯了什么?

您可以在頁面底部附近的Oracle的Object Ordening Java Tutorial中閱讀:

您可能想要使用更簡單的方法替換Comparator中的最終return語句:

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

除非你絕對確定沒有人會有負面的員工編號,否則不要這樣做! 這個技巧一般不起作用,因為有符號整數類型不足以表示兩個任意有符號整數的差異。 如果i是一個大的正整數且j是一個大的負整數,i-j將溢出並返回一個負整數。 由此產生的比較器違反了我們一直在討論的四個技術限制之一(傳遞性)並產生可怕的,微妙的錯誤。 這不是純粹的理論問題; 人們被它燒了。

這里描述的情況是OP遇到的情況:兩個整數之間的差異大於Integer.MAX_VALUE ,因此在比較期間會溢出,從而導致意外排序。

我只是做了@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);
    }
}

我得到了

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

我們可以看到

\n

List#sort(Comparator)以相反的順序將值應用於給定的 Comparator

  1. 使用給定的Comparator
  2. 當它適用於-12147483647
  3. (y - x)部分( 2147483647 - -1 )溢出為-2147483648 ,為負數,
  4. 而且-1確實小於2147483647

這是源代碼。

清單#排序(比較)

@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);
    }
}

數組排序#(比較)

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

DualPovotQuicksort#排序()

在我們開始之前,你需要知道,如果compare(x,y) < 0根據其設計compare(x,y) < 0 pair(x,y)視為有序的
(就像自然(升序)順序一樣:如果x<yxy<0 )。


整數溢出

在數學世界中,如果對(x,y)中的x和y按升序排列,我們可以將其寫為x<y ,也可以將其重寫為xy<0 降序可以表示為x>y ,可以將其重寫為xy>0
但這種重寫只有在數學世界中才有可能。 在IT世界中,像int這樣的數字類型有它們的最小值和最大值,如果我們嘗試計算超出該范圍的值,我們將面臨整數溢出 你的例子就是其中一個例子。 如果x = -1y = 2147483647那么比較器計算yx將返回-2147483648

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

而不是積極的2147483648

因此,返回不正確 (和否定)的結果,使排序算法“認為” xy正確

等等,如果結果是錯誤的,那么我們如何以升序 [-1, 2147483647]得到結果元素? 那個“不正確”的命令不應該下降嗎?

不,因為比較器返回yx描述了降序 看一看。 Comparator.compare(x,y)<0時,任何Comparator.compare(x,y)中使用的元素xy都被認為是正確的順序。 如果我們使用比較器的代碼,我們將得到yx<0 ,順序為y<x (或更簡單的x>y )。

如果我們更改列表中的一些元素,也可以很容易地觀察到它

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

我們將在排序后得到

[5, 2, -1]

簡而言之:

  • 排序算法使用描述降序的 Comparator
  • 但由於比較器出錯(由整數溢出引起),它不通知排序算法需要“改變順序” -12147483647以便它們保持在他們的位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM