排序12项的最佳算法是什么

时间:2014-03-27 13:09:39

标签: java performance algorithm sorting

我需要对startIndexstartIndex + 12之间的整数数组进行排序。此操作对我的表现至关重要。

您建议我使用什么算法?

现在我正在使用Bubble sort并且表现不佳...

更新:很抱歉找不到详细信息。我正在使用随机数组。我经常这样做,我在Java工作。

更新2:我不确定插入排序是个好主意,因为我使用的是本机数组而不是ArrayList。所以我需要自己实现插入,或者将它与泡泡搜索结合起来。

5 个答案:

答案 0 :(得分:8)

您可以尝试这种排序网络:

http://jgamble.ripco.net/cgi-bin/nw.cgi?inputs=12&algorithm=best&output=svg

这是12项的最佳配置。这意味着,最小化操作所需的比较器和深度(如果可以并行工作则可以连续执行)。

要利用并行化,请使用SIMD(SEE)指令。我不知道如何用Java做到这一点。

答案 1 :(得分:2)

对于12个项目,可能是插入排序。它通常具有O(n ^ 2)排序算法的最佳经验性能。对于如此小的集合,O(n log n)算法可能有点过分,算法的复杂性通常意味着它们不会得到回报,直到你排序的集合更大。

当然,如果你真的想要挤出最后一滴性能,你可能需要编写一些程序集并在寄存器或其他东西中进行。

如果你知道它们是有界的,基数排序也可能是一个很好的方法。

答案 2 :(得分:1)

我还会尝试硬编码的合并排序。 首先用硬代码(没有索引变量)对每个连续的3组进行排序。 这3次比较时间为4 = 12。

然后合并前两组3。 那3次比较时间2 = 6。

然后合并两组6。 这是6次比较。

总共24次比较(和数据移动)。

这个可能比72次比较和可能的互换更快。

我在汇编程序中逐步完成它,看看是否有任何说明没有减轻它们的重量。

答案 3 :(得分:1)

我实施了小测试,一次使用Arrays.sort,一次使用自己的排序实现,基于https://stackoverflow.com/a/22688819中@ypnos引用的排序网络。

但是, NOT 这个比较太严肃了。它不是一个非常复杂的微基准标记,肯定还有很多影响因素尚未考虑。我想到的一个问题是:12个元素的片段是否线性排序?也就是说,您首先排序元素[0,12),然后排序[12,24],依此类推,还是分散在数组中的片段?由于缓存,这可能会对性能产生影响。对所有方法而言,这种影响可能相同,但仍应予以考虑。

在任何情况下,似乎都可以通过这样的分拣网络(或者#34;展开的"排序方法)来挤出一点点性能。

但为了进行比较,我添加了一种并行方法,其中对12个元素段进行排序的任务分布在所有可用内核中,并且似乎可以通过这种方式实现显着的加速。因此,您通常应考虑对此任务进行某种并行化。

(从-Xmx2000m开始,为大型阵列提供足够的内存)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SmallSortTest
{
    public static void main(String[] args)
    {
        Random random = new Random(0);
        for (int size=8000000; size<=8000000*10; size+=8000000)
        {
            int array[] = createRandomArray(size, 0, 1000, random);

            int array0[] = array.clone();
            testArrays(array0);

            int array1[] = array.clone();
            testOwn(array1);

            int array2[] = array.clone();
            testParallel(array2);

            if (!Arrays.equals(array0, array1)) System.out.println("Error");
            if (!Arrays.equals(array0, array2)) System.out.println("Error");
        }
    }

    private static void testArrays(int array[])
    {
        long before = System.nanoTime();
        for (int i=0; i<array.length/12; i++)
        {
            Arrays.sort(array, i*12, i*12+12);
        }
        long after = System.nanoTime();

        System.out.println(
            "Arrays   size "+array.length+
            " duration "+(after-before)*1e-6+
            ", some result "+array[array.length/2]);
    }

    private static void testOwn(int array[])
    {
        long before = System.nanoTime();
        for (int i=0; i<array.length/12; i++)
        {
            sort(array, i*12);
        }
        long after = System.nanoTime();
        System.out.println(
            "Own      size "+array.length+
            " duration "+(after-before)*1e-6+
            ", some result "+array[array.length/2]);
    }

    private static void testParallel(final int array[])
    {
        int n = Runtime.getRuntime().availableProcessors();
        ExecutorService executor = Executors.newFixedThreadPool(n);

        int batchSize = (int)Math.ceil((double)array.length / 12  / n);
        final List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
        for (int i=0; i<n; i++)
        {
            final int minIndex = (i+0)*batchSize;
            final int maxIndex = Math.min(array.length, (i+1)*batchSize);
            Runnable runnable = new Runnable()
            {
                @Override
                public void run()
                {
                    for (int i=minIndex; i<maxIndex; i++)
                    {
                        Arrays.sort(array, i*12, i*12+12);
                    }
                }
            };
            tasks.add(Executors.callable(runnable));
        }

        long before = System.nanoTime();
        try
        {
            executor.invokeAll(tasks);
        }
        catch (InterruptedException e1)
        {
            Thread.currentThread().interrupt();
        }        
        long after = System.nanoTime();

        executor.shutdown();
        try
        {
            executor.awaitTermination(5, TimeUnit.SECONDS);
        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }

        System.out.println(
            "Parallel size "+array.length+
            " duration "+(after-before)*1e-6+
            ", some result "+array[array.length/2]);
    }

    private static void sort(int array[], int startIndex)
    {
        int i0 = startIndex+11;
        int i1 = startIndex+10;
        int i2 = startIndex+9;
        int i3 = startIndex+8;
        int i4 = startIndex+7;
        int i5 = startIndex+6;
        int i6 = startIndex+5;
        int i7 = startIndex+4;
        int i8 = startIndex+3;
        int i9 = startIndex+2;
        int i10 = startIndex+1;
        int i11 = startIndex+0;

        if (array[i0] < array[i1]) swap(array, i0, i1);
        if (array[i2] < array[i3]) swap(array, i2, i3);
        if (array[i4] < array[i5]) swap(array, i4, i5);
        if (array[i6] < array[i7]) swap(array, i6, i7);
        if (array[i8] < array[i9]) swap(array, i8, i9);
        if (array[i10] < array[i11]) swap(array, i10, i11);

        if (array[i1] < array[i3]) swap(array, i1, i3);
        if (array[i5] < array[i7]) swap(array, i5, i7);
        if (array[i9] < array[i11]) swap(array, i9, i11);
        if (array[i0] < array[i2]) swap(array, i0, i2);
        if (array[i4] < array[i6]) swap(array, i4, i6);
        if (array[i8] < array[i10]) swap(array, i8, i10);

        if (array[i1] < array[i2]) swap(array, i1, i2);
        if (array[i5] < array[i6]) swap(array, i5, i6);
        if (array[i9] < array[i10]) swap(array, i9, i10);
        if (array[i0] < array[i4]) swap(array, i0, i4);
        if (array[i7] < array[i11]) swap(array, i7, i11);

        if (array[i1] < array[i5]) swap(array, i1, i5);
        if (array[i6] < array[i10]) swap(array, i6, i10);
        if (array[i3] < array[i7]) swap(array, i3, i7);
        if (array[i4] < array[i8]) swap(array, i4, i8);

        if (array[i5] < array[i9]) swap(array, i5, i9);
        if (array[i2] < array[i6]) swap(array, i2, i6);
        if (array[i0] < array[i4]) swap(array, i0, i4);
        if (array[i7] < array[i11]) swap(array, i7, i11);
        if (array[i3] < array[i8]) swap(array, i3, i8);

        if (array[i1] < array[i5]) swap(array, i1, i5);
        if (array[i6] < array[i10]) swap(array, i6, i10);
        if (array[i2] < array[i3]) swap(array, i2, i3);
        if (array[i8] < array[i9]) swap(array, i8, i9);

        if (array[i1] < array[i4]) swap(array, i1, i4);
        if (array[i7] < array[i10]) swap(array, i7, i10);
        if (array[i3] < array[i5]) swap(array, i3, i5);
        if (array[i6] < array[i8]) swap(array, i6, i8);

        if (array[i2] < array[i4]) swap(array, i2, i4);
        if (array[i7] < array[i9]) swap(array, i7, i9);
        if (array[i5] < array[i6]) swap(array, i5, i6);

        if (array[i3] < array[i4]) swap(array, i3, i4);
        if (array[i7] < array[i8]) swap(array, i7, i8);
    }

    private static void swap(int array[], int i0, int i1)
    {
        int temp = array[i0];
        array[i0] = array[i1];
        array[i1] = temp;
    }


    private static int[] createRandomArray(int size, int min, int max, Random random)
    {
        int array[] = new int[size];
        for (int i=0; i<size; i++)
        {
            array[i] = min+random.nextInt(max-min);
        }
        return array;
    }
}

答案 4 :(得分:1)

QuickSort和MergeSort对于如此小的阵列大小无效。 我会使用insertSort,我测量的速度比bubbleSort快。

private static void insertionSort(int[] intArray) {
    for(int i=1; i<intArray.length; i++){
        int temp = intArray[i];
        int j;
        for(j=i-1; j>=0 && temp<intArray[j]; j--){
            intArray[j+1]=intArray[j];
        }
        intArray[j+1] = temp;
    }
}