使用自定义比较器对原语数组进行排序,而不将其转换为对象



在Java中使用自定义比较器(或键)函数和对原始数组进行排序,而不转换为对象数组(为了性能†)的最简单方法是什么?

†(只是一个预防措施,我不是问不转换为对象是否是一个好的决定从性能POV。)

使用自定义比较器对原始值数组进行排序是标准Java库不支持的。

你可以很容易地实现一个简单的排序(例如bubblesort - O(N^2))从头开始,但问题是,对于足够大的数组,你不转换为盒装类型所节省的费用会在效率较低的排序算法中丢失。

所以你的选择是:

  • 从头开始实现高性能排序(合并排序,修改快速排序等)

  • 找到一个现有的不支持比较器的基本类型的高性能排序,并修改它。

  • 看看你是否能找到一个合适的支持原生数组和比较器的第三方库。(我还没有找到…)

(注意:Comparator接口在这里不起作用。不适合比较基本类型

在Java 8中,您可以让sort方法采用函数接口。这是从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))。

最难但最快的:MergeSort((O(Nlog(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));
}

最新更新