簡體   English   中英

使用自定義比較器對原始數組進行排序,而無需轉換為對象

[英]Sort an array of primitives with a custom comparator and without converting to objects

在Java中使用自定義比較器(或鍵)函數對原始數組進行排序而不轉換為對象數組的最簡單方法是什么(性能†)。

†(為防萬一,我不是在問是否從性能POV轉換為對象是否是一個好的決定。)

標准Java庫不支持使用自定義比較器對原始值數組進行排序。

您可以輕松地從頭開始實現簡單的排序(例如bubbleort- O(N^2) ),但是問題是,對於足夠大的數組,通過不轉換為盒裝類型而節省的費用在效率較低的排序算法中會丟失。

因此,您的選擇是:

  • 從頭開始實施高性能排序(合並排序,修改后的快速排序等)。

  • 查找不支持比較器的原始類型的現有高性能排序,然后對其進行修改。

  • 看看您是否可以找到合適的第三方庫來支持數組和比較器。 (我沒有找到一個...)

(注意: Comparator接口在這里不起作用。它不適用於比較基本類型。)

在Java 8中,您可以讓您的排序方法帶有一個函數接口。 這是OpenJDK的修改代碼(版權1997-2007 Sun Microsystems,Inc. GPLv2 ):

import java.util.function.LongBinaryOperator;

public class ArraySort {
    public static void sort(long[] x, LongBinaryOperator op) {
        sort1(x, 0, x.length, op);
    }

    private static void sort1(long x[], int off, int len, LongBinaryOperator op) {
        if (len < 7) {
            for (int i=off; i<len+off; i++)
                // Use custom comparator for insertion sort fallback
                for (int j=i; j>off && (op.applyAsLong(x[j-1], x[j]) > 0); j--)
                    swap(x, j, j-1);
            return;
        }

        int m = off + (len >> 1);
        if (len > 7) {
            int l = off;
            int n = off + len - 1;
            if (len > 40) {
                int s = len/8;
                l = med3(x, l,     l+s, l+2*s);
                m = med3(x, m-s,   m,   m+s);
                n = med3(x, n-2*s, n-s, n);
            }
            m = med3(x, l, m, n);
        }
        long v = x[m];

        int a = off, b = a, c = off + len - 1, d = c;
        while(true) {
            // Use custom comparator for checking elements
            while (b <= c && (op.applyAsLong(x[b], v) <= 0)) {
                if (x[b] == v)
                    swap(x, a++, b);
                b++;
            }
            // Use custom comparator for checking elements
            while (c >= b && (op.applyAsLong(x[c], v) >= 0)) {
                if (x[c] == v)
                    swap(x, c, d--);
                c--;
            }
            if (b > c)
                break;
            swap(x, b++, c--);
        }

        int s, n = off + len;
        s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);
        s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);

        if ((s = b-a) > 1)
            sort1(x, off, s, op);
        if ((s = d-c) > 1)
            sort1(x, n-s, s, op);
    }

    private static void swap(long x[], int a, int b) {
        long t = x[a];
        x[a] = x[b];
        x[b] = t;
    }

    private static void vecswap(long x[], int a, int b, int n) {
        for (int i=0; i<n; i++, a++, b++)
            swap(x, a, b);
    }

    private static int med3(long x[], int a, int b, int c) {
        return (x[a] < x[b] ?
                (x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
                (x[b] > x[c] ? b : x[a] > x[c] ? c : a));
    }
}

並使用lambda或實現LongBinaryOperator接口的任何其他方式調用它:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        long x[] = {5, 5, 7, 1, 2, 5, 8, 9, 23, 5, 32, 45, 76};
        ArraySort.sort(x, (a, b) -> b - a);         // sort descending
        System.out.println(Arrays.toString(x));
    }
}

輸出:

[76, 45, 32, 23, 9, 8, 7, 5, 5, 5, 5, 2, 1]

您可以只構建自己的比較函數,並使用一種排序算法

最簡單,最慢: BubbleSort (O(N ^ 2))。

最辛苦,但最快: 歸並 ((O(n日志(N))。

現在在這兩種算法中,您都有詢問A> B的部分,在這一部分中,您應該放置比較函數。

boolean compare(int x, int y){
     if(/* your crazy compare condition */)
         return true;
     else return false; 
}

冒泡排序示例:

    procedure bubbleSort( A : list of sortable items )
   repeat     
     swapped = false
     for i = 1 to length(A) - 1 inclusive do:
       /* if this pair is out of order */
       if compare(A[i],A[i-1]) then // Notcie the compare instead of A[i] > A[i-1]
         /* swap them and remember something changed */
         swap( A[i-1], A[i] )
         swapped = true
       end if
     end for
   until not swapped
end procedure

希望這可以幫助

創建一個Integer列表,表示數組中的索引,對列表進行排序。 您可以多次重用索引列表以進行多種排序。

我從Java 6的Arrays.java復制了以下內容,並根據需要進行了修改。 它在較小的數組上使用插入排序,因此應該比純快速排序更快。

/**
 * Sorts the specified sub-array of integers into ascending order.
 */
private static void sort1(int x[], int off, int len) {
    // Insertion sort on smallest arrays
    if (len < 7) {
        for (int i=off; i<len+off; i++)
            for (int j=i; j>off && x[j-1]>x[j]; j--)
                swap(x, j, j-1);
        return;
    }

    // Choose a partition element, v
    int m = off + (len >> 1);       // Small arrays, middle element
    if (len > 7) {
        int l = off;
        int n = off + len - 1;
        if (len > 40) {        // Big arrays, pseudomedian of 9
            int s = len/8;
            l = med3(x, l,     l+s, l+2*s);
            m = med3(x, m-s,   m,   m+s);
            n = med3(x, n-2*s, n-s, n);
        }
        m = med3(x, l, m, n); // Mid-size, med of 3
    }
    int v = x[m];

    // Establish Invariant: v* (<v)* (>v)* v*
    int a = off, b = a, c = off + len - 1, d = c;
    while(true) {
        while (b <= c && x[b] <= v) {
            if (x[b] == v)
                swap(x, a++, b);
            b++;
        }
        while (c >= b && x[c] >= v) {
            if (x[c] == v)
                swap(x, c, d--);
            c--;
        }
        if (b > c)
            break;
        swap(x, b++, c--);
    }

    // Swap partition elements back to middle
    int s, n = off + len;
    s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);
    s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);

    // Recursively sort non-partition-elements
    if ((s = b-a) > 1)
        sort1(x, off, s);
    if ((s = d-c) > 1)
        sort1(x, n-s, s);
}

/**
 * Swaps x[a] with x[b].
 */
private static void swap(int x[], int a, int b) {
    int t = x[a];
    x[a] = x[b];
    x[b] = t;
}

/**
 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
 */
private static void vecswap(int x[], int a, int b, int n) {
    for (int i=0; i<n; i++, a++, b++)
        swap(x, a, b);
}

/**
 * Returns the index of the median of the three indexed integers.
 */
private static int med3(int x[], int a, int b, int c) {
    return (x[a] < x[b] ?
            (x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
            (x[b] > x[c] ? b : x[a] > x[c] ? c : a));
}

暫無
暫無

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

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