簡體   English   中英

為什么這個比較器沒有正確地分離奇數和偶數

[英]Why doesn't this Comparator segregate odd and even numbers correcly

以下是我嘗試(失敗和成功)將數組中的奇數和偶數分開的嘗試。 預期的輸出是在數組中的奇數之前有所有的偶數。 因此,有效的輸出是

2 4 6 8 10 9 7 5 3 1 

注釋中的一個是無效的版本,另一個版本有效。

在失敗的版本中,我想知道為什么它不起作用。 我正在做的是,如果第一個數字是奇數,第二個數字是偶數,我將其交換。 在所有其他情況下,我不進行任何交換,這是可以的,因為如果兩個數字都是偶數,或者兩個數字都是奇數,或者如果偶數已經在奇數之前,則不需要交換。已經保持了預期輸出的模式。

public void evenOddComparator()
    {
        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 a1, Integer a2)
//                {
//                    if( ((a1%2) == 1) && ((a2%2) == 0))
//                        return 1;
//                    return 0;
//                }

                final int BEFORE = -1;
                final int EQUAL = 0;
                final int AFTER = 1;

                @Override
                public int compare(Integer o1, Integer o2) {
                    if (o1 % 2 == 0 && o2 % 2 != 0) {
                        return BEFORE;
                    } else if (o1 % 2 != 0 && o2 % 2 == 0) {
                        return AFTER;
                    } else if (o1 % 2 == 0 && o2 % 2 == 0) {
                        return o1.compareTo(o2);
                    } else if (o1 % 2 != 0 && o2 % 2 != 0) {
                        return o2.compareTo(o1);
                    }

                    return EQUAL;
                }
            });
        print(a);   
    }

您能幫我理解為什么注釋掉的邏輯未按預期工作嗎?

帶注釋的代碼的根本問題是,您打破了所有比較實現的預期一致性條件:

實現者必須確保所有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 compare 2 = 1和2 compare 3 =0。這使您的實現違反了Java中所有排序算法的假定前提,因此不起作用。

之所以如此重要,是因為否則最終順序將取決於恰好構成比較的每一面的元素。 如果算法碰巧比較2到3而不是3到2,那么您將以不同的順序結束。 該文檔堅持要通過交換邊來精確地返回否定結果,以便所有實現可以任意確定哪些元素構成比較中的第一個和第二個參數。 這樣可以提高效率(順便說一句,可以匹配比較的數學定義)。

我還注意到,在您的問題中,您暗指實施比較旨在表示排序操作中要交換的內容和不交換的內容。 那根本不是真的。 有許多不同的排序算法,其中許多不交換任何內容-它們復制或拆分並重新加入,或使用許多其他技術。 或者比較可能是找到最大或最小元素。

因此,當您定義比較時,並不表示要交換什么。 相反,您要定義較小的值和較大的值(在此比較內),然后將如何使用的細節留給正在調用的算法。 您永遠不要以為您知道該算法的工作原理(特別是因為它將在JVM和JVM之間以及版本之間變化)。 只需遵循文檔中的條件,無論算法如何更改,都可以保證它能正常工作。

順便說一句,您可以通過以下語句實現結果:

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

這只是將每個數字轉換為0或1,具體取決於它是偶數還是奇數,然后進行比較。 它使用Math.floorMod以便它可以正確處理負數(您的實現不能這樣做)。

比較功能用於確定較大的數字。 您必須將任何奇數的值評估為更大。

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

暫無
暫無

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

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