简体   繁体   English

使用自定义比较器对原始数组进行排序,而无需转换为对象

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

What's the simplest way to sort a primitive array in Java with a custom comparator (or key) function and without converting to an array of objects (for performance †). 在Java中使用自定义比较器(或键)函数对原始数组进行排序而不转换为对象数组的最简单方法是什么(性能†)。

† (Just a precaution, I'm not asking whether not converting to objects is a good decision from a performance POV.) †(为防万一,我不是在问是否从性能POV转换为对象是否是一个好的决定。)

Sorting of an array of primitive values with a custom comparator is not supported by the standard Java libraries. 标准Java库不支持使用自定义比较器对原始值数组进行排序。

You could easily implement your a simple sort ( eg bubblesort - O(N^2) ) from scratch, but the problem is that for large enough arrays the saving you make by not converting to boxed types is lost in the less efficient sorting algorithm. 您可以轻松地从头开始实现简单的排序(例如bubbleort- O(N^2) ),但是问题是,对于足够大的数组,通过不转换为盒装类型而节省的费用在效率较低的排序算法中会丢失。

So your choices are: 因此,您的选择是:

  • Implement a high performance sort (mergesort, modified quicksort, etc) from scratch. 从头开始实施高性能排序(合并排序,修改后的快速排序等)。

  • Find an existing high performance sort for primitive types that doesn't support comparators, and modify it. 查找不支持比较器的原始类型的现有高性能排序,然后对其进行修改。

  • See if you can find a suitable 3rd-party library that supports ptimitive arrays and comparators. 看看您是否可以找到合适的第三方库来支持数组和比较器。 (I haven't managed to find one ...) (我没有找到一个...)

(Note: the Comparator interface won't work here. It is not suitable for comparing primitive types.) (注意: Comparator接口在这里不起作用。它不适用于比较基本类型。)

In Java 8 you can have your sort method take a function interface. 在Java 8中,您可以让您的排序方法带有一个函数接口。 This is modified code from OpenJDK (Copyright 1997-2007 Sun Microsystems, Inc. GPLv2 ): 这是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));
    }
}

And call it with lambdas or anything else implementing the LongBinaryOperator interface: 并使用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));
    }
}

Output: 输出:

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

You can just build your own compare functions , and use one of the sort algorithms 您可以只构建自己的比较函数,并使用一种排序算法

easiest and slowest: BubbleSort ( O(N^2) ). 最简单,最慢: BubbleSort (O(N ^ 2))。

hardest but fastest : MergeSort ( (O(Nlog(n) ) . 最辛苦,但最快: 归并 ((O(n日志(N))。

now in both algos you have the part that asks if A > B , in this part you should put your compare func. 现在在这两种算法中,您都有询问A> B的部分,在这一部分中,您应该放置比较函数。

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

example in bubble sort : 冒泡排序示例:

    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

hope this helps 希望这可以帮助

Create a list of Integer representing the indexes in the array, sort the list. 创建一个Integer列表,表示数组中的索引,对列表进行排序。 You can reuse the list of indexes many times for many sorts. 您可以多次重用索引列表以进行多种排序。

I copied the following from Java 6's Arrays.java and modified it to my needs. 我从Java 6的Arrays.java复制了以下内容,并根据需要进行了修改。 It uses insertion sort on smaller arrays so it should be faster than pure quicksort. 它在较小的数组上使用插入排序,因此应该比纯快速排序更快。

/**
 * 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