Java: Racing Arrays.sort

别等时光非礼了梦想. 提交于 2019-12-10 20:09:34

问题


I created some improvement to QuickSort and decide to test it against Java Arrays.sort().

The results are fascinating:

On Java 6:

  • My Time / System Time = 74 / 83 = 0.891566265060241
  • My Time / System Time = 75 / 79 = 0.9493670886075949
  • My Time / System Time = 75 / 84 = 0.8928571428571429

On Java 7:

  • My Time / System Time = 115 / 70 = 1.6428571428571428
  • My Time / System Time = 101 / 76 = 1.3289473684210527
  • My Time / System Time = 102 / 61 = 1.6721311475409837

As you can see my algorithm performs better on Java 6, how ever it have a dramatic drop on Java 7 witch I don't understand. May be you can find the reason why?

Edit: How does my algorithm works:

  • Step 1: Take 3 numbers, sort them, use the middle number as pivot
  • Step 2: Take all the numbers bigger than pivot to the right and all the numbers smaller than pivot to the left, and place pivot in it's final position in the sorted array. This actually implemented in O(N).
  • Step 3: Recursively repeat step 1 and 2 for left and right sides. When you rich sub array smaller than 12 elements use network sort to sort it.

My source code

public class QuickSort {

    public static void sort(int[] source) {
        int buffer[] = new int[source.length];
        concatenate(source, buffer, 0, source.length);
    }

    private static void concatenate(int[] source, int[] buffer, int low, int high) {
        int count = high - low;
        int lowBuffer = low;
        int highBuffer = high;

        if (count < 2) {
            return;
        }

        if (count < 12) {
            networkSort(source, buffer, low, count);
            return;
        }
        int pivotIndex = bestOfThree(source, low);
        int value = source[pivotIndex];

        for (int i = low; i < high; i++) {
            if (i == pivotIndex) {
                continue;
            }
            if (source[i] < value) {
                buffer[lowBuffer] = source[i];
                source[lowBuffer] = buffer[lowBuffer];
                lowBuffer++;
            }
            else {
                highBuffer--;
                buffer[highBuffer] = source[i];
            }
        }

        buffer[lowBuffer] = source[lowBuffer] = value;
        for (int i = lowBuffer; i < high; i++) {
            source[i] = buffer[i];
        }

        concatenate(source, buffer, lowBuffer + 1, high);
        concatenate(source, buffer, low, lowBuffer);
    }

    private static int bestOfThree(int[] source, int low) {
        int a = low;
        int b = a + 1;
        int c = a + 2;
        int median = -1;

        if (source[a] >= source[b] && source[a] >= source[c]) {
            if (source[b] < source[c]) {
                median = c;
            }
            else {
                median = b;
            }
        }
        else if (source[b] >= source[a] && source[b] >= source[c]) {
            if (source[a] < source[c]) {
                median = c;
            }
            else {
                median = a;
            }
        }
        else if (source[c] >= source[a] && source[c] >= source[b]) {
            if (source[a] < source[b]) {
                median = b;
            }
            else {
                median = a;
            }
        }
        return median;
    }

    private static int[][] networkSort = { 
            { 0, 1 }, 
            { 1, 2, 0, 2, 0, 1 },
            { 0, 1, 2, 3, 0, 2, 1, 3, 1, 2 },
            { 0, 1, 3, 4, 2, 4, 2, 3, 1, 4, 0, 3, 0, 2, 1, 3, 1, 2 },
            { 1, 2, 4, 5, 0, 2, 3, 5, 0, 1, 3, 4, 2, 5, 0, 3, 1, 4, 2, 4, 1, 3, 2, 3 },
            { 1, 2, 3, 4, 5, 6, 0, 2, 3, 5, 4, 6, 0, 1, 4, 5, 2, 6, 0, 4, 1, 5, 0, 3, 2, 5, 1, 3, 2, 4, 2, 3 }, 
            { 0, 1, 2, 3, 4, 5, 6, 7, 0, 2, 1, 3, 4, 6, 5, 7, 1, 2, 5, 6, 0, 4, 3, 7, 1, 5, 2, 6, 1, 4, 3, 6, 2, 4, 3, 5, 3, 4 },
            { 0, 1, 3, 4, 6, 7, 1, 2, 4, 5, 7, 8, 0, 1, 3, 4, 6, 7, 2, 5, 0, 3, 1, 4, 5, 8, 3, 6, 4, 7, 2, 5, 0, 3, 1, 4, 5, 7, 2, 6, 1, 3, 4, 6, 2, 4, 5, 6, 2, 3 },
            { 4, 9, 3, 8, 2, 7, 1, 6, 0, 5, 1, 4, 6, 9, 0, 3, 5, 8, 0, 2, 3, 6, 7, 9, 0, 1, 2, 4, 5, 7, 8, 9, 1, 2, 4, 6, 7, 8, 3, 5, 2, 5, 6, 8, 1, 3, 4, 7, 2, 3, 6, 7, 3, 4, 5, 6, 4, 5 },
            { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 0, 2, 4, 6, 8, 10, 1, 2, 5, 6, 9, 10, 0, 4, 3, 7, 1, 5, 6, 10, 4, 8, 5, 9, 2, 6, 0, 4, 3, 8, 1, 5, 6, 10, 2, 3, 8, 9, 1, 4, 7, 10, 3, 5, 6, 8, 2, 4, 7, 9, 5, 6, 3, 4, 7, 8 }
        };

    private static int tmp;

    private static void networkSort(int[] source, int[] buffer, int low, int count) {
        int[] networkData = networkSort[count - 2];

        for (int i = 0; i < networkData.length; i += 2) {
            int index1 = low + networkData[i];
            int index2 = low + networkData[i + 1];

            if (source[index1] > source[index2]) {
                tmp = source[index1];
                buffer[index1] = source[index1] = source[index2];
                buffer[index2] = source[index2] = tmp;
            }
        }
    }   
}

Base testing class

public abstract class Test {
    protected int[][] buffer;
    private final Random random = new Random();

    public int numberOfTests = 100;
    public int maxValue = 1000;
    public int numberOfItems = 100;

    protected void createBuffer() {
        buffer = new int[numberOfTests][];
        for (int i = 0; i < numberOfTests; i++) {
            int[] list = new int[numberOfItems];
            addRandomNumbers(list);
            buffer[i] = list;
        }
    }

    protected void createBuffer(int...parametes) {
        buffer = new int[1][];
        buffer[0] = parametes;
    }

    protected void addRandomNumbers(int[] list) {
        for (int i = 0; i < numberOfItems; i++) {
            int value = random.nextInt(maxValue);
            list[i] = value;
        }
    }

    protected int[][] cloneBuffer() {
        int[][] clonedBuffer =  new int[numberOfTests][];
        for(int i = 0; i < buffer.length; i++){
            int[] clonedList = new int[buffer[i].length];
            int[] list = buffer[i];
            for (int j = 0; j < list.length; j++) {
                int element = list[j];
                clonedList[j] = element;
            }
            clonedBuffer[i] = clonedList;
        }
        return clonedBuffer;
    }

    public abstract void test();
}

Performance Test

public class PerformanceTest extends Test {

    private final Timer timer = new Timer();

    public void test() {
        createBuffer();

        timer.reset();
        testSystem();
        timeResoult("System");

        timer.reset();
        testMy();
        timeResoult("My List");
    }

    public void test(int numberOfTests) {
        long myTotalTime = 0;
        long systemTotalTime = 0;

        for (int i = 0; i < numberOfTests; i++) {
            createBuffer();

            timer.reset();
            testSystem();
            long systemTime = timeResoult();
            systemTotalTime += systemTime;

            timer.reset();
            testMy();
            long myTime = timeResoult();
            myTotalTime += myTime;

            System.out.println("My Time / System Time = " + myTime + " / " + systemTime + " = \t"
                    + ((double) myTime / systemTime));
        }
        System.out.println("My Time / System Time = " + ((double) myTotalTime / systemTotalTime));

    }

    private long timeResoult() {
        return timeResoult(null);
    }

    private long timeResoult(String source) {
        long time = timer.check();
        if (source != null) {
            System.out.println(source + ">\tTime: " + time);
        }
        return time;
    }

    private void testMy() {
        int[][] buffer = cloneBuffer();
        for (int i = 0; i < numberOfTests; i++) {
            int[] list = buffer[i];
            QuickSort.sort(list);
        }
    }

    private void testSystem() {
        int[][] buffer = cloneBuffer();
        for (int i = 0; i < numberOfTests; i++) {
            int[] list = buffer[i];
            Arrays.sort(list);
        }
    }
}

Main

public static void main(String[] args) {
        PerformanceTest testBasics = new PerformanceTest();
        testBasics.numberOfTests = 1000;
        testBasics.numberOfItems = 1000;
        testBasics.maxValue = 1000000;
        testBasics.test(100);
    }

回答1:


They changed the sort algorithm of Arrays.sort for Java 7. For sorting objects, Arrays.sort now uses algorithm called Timsort and dual-pivot quicksort for primitives. More info in this answer.

If you really want to use the old one, apparently you can set a system property java.util.Arrays.useLegacyMergeSort.

See Java 7 compatibility documentation.



来源:https://stackoverflow.com/questions/22691435/java-racing-arrays-sort

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!