并行合并排序性能

时间:2011-12-08 18:16:33

标签: parallel-processing mergesort

如果我将其并行化,我试图直观地了解我可以加快合并排序的速度。

到目前为止我的想法:

如果N是要排序的数组中的元素数,则log(base 2)N是我需要的最大核心数。我相信这是因为mergesort中有2 * log(base 2)N + 1级别。首先,你将它一遍又一遍地将其分解,然后你反复合并两个已排序的数组,直到你再次有一个N个项目的数组(现在它已被排序)。

我正在试图弄清楚这实际上会提高多少性能。我认为随着我们向算法的中间移动,由于额外的核心而导致的性能提升会增加,因为我们可以使用更多核心。假设我在未排序的数组中有16个项目。我只需要使用一个核心将其分解为两个8项目数组,然后我可以使用两个核心将它们分成四个4项目数组等。

因此,对于每个分割级别,性能将增加两倍,然后对于每个合并级别减少两个......对吗?我在这里走在正确的轨道上吗?

另外,为什么我们不能首先合并未排序数组中的前两项,然后合并接下来的两项,依此类推。基本上摆脱了算法的前半部分?

思想?

我应该在math.stackexchange.com上问这个吗?对不起,如果是这样......我真的不知道

2 个答案:

答案 0 :(得分:0)

如果要通过并行化提高MergeSort的性能,则应该并行化拆分(合并结果之前执行的部分)。我假设你有多个CPU节点。

<强>分裂: 让当前的CPU节点保留一半的数组,并将另一半的CPU节点提供给另一个CPU节点。继续重复这个过程。当你深入到树中时,并行性会增加(如你所提到的)

基本情况: 当数据是一个项目时,当前CPU节点将其发送回其父节点。 在进行任何合并之前,父节点将等待子节点传递数据。

<强>合并: 一旦接收到来自节点子节点的数据,节点(该子节点的父节点)就可以开始将接收到的数据与其自己的数据合并。合并完成后,它会将其传递给其父节点,依此类推。由于每个节点都是单独的CPU,因此并行执行较低级别的合并。当我们上树时,这种并行性会降低。 (就像你提到的那样)

这应该加快合并排序。

但是,维基百科http://en.wikipedia.org/wiki/Merge_sort#Parallel_processing上的这篇文章表明,通过并行化和专门化(以及在数据大小<11时抛出插入排序),可以加快合并步骤到O(1)

我很好奇为什么你不使用Quicksort。它很适合并行化!

编辑:

  

另外,为什么我们不能开始合并前两个项目   未排序的数组,然后是下两个,依此类推。基本上摆脱了   算法的前半部分?

并回答您的问题:

这就是合并排序正在做的事情,它正在合并前2个,接下来的2个,依此类推,但为了得到它们,它使用了递归。这使得运行时O(n * 2log(n))因为有2个树(一个在分割时创建,一个在合并回一个大列表时创建)。这出现在O(nlog(n))。

采取你的想法,从底部开始,取2乘2的数字并对它们进行排序。然后扩大边界以包含2个块(每个w 2个数字)4个数字......等等。你正在建造一棵树,从树叶到树根。这类似于锦标赛算法(尽管你只有一个胜利者 - 树的根)。

运行时:首先你有n个数字。你循环所以设置每2个数字O(n / 2),下一个O(n / 4),下一个O(n / 8)等边界。 构建此树需要O(log(n))。但是你仍然需要将其他数字合并到一个列表中。由于您有n个数字,即n * O(nlogn),它为您提供与merge sort nlogn相同的运行时。

<强>要点: 所以我想说的是你从底层合并的想法仍然是长久的。你正在摆脱其中一棵树,所以速度并不快。

答案 1 :(得分:0)

众所周知,Dual Pivot QuickSort在串行版本中击败了Merge Sort。我认为DPQ的并行形式可能真的是有史以来最快的排序算法。原因是它具有比MergeSort低的常数因子,并且其最坏情况时间复杂度仅出现1 /(n!)的概率。如果N很大,则更喜欢DPQ,如果可能的话,可能是多线程的。但并行性有一个支点或限制,低于限制因其线程管理而变慢。超出限制它会更快。如果您感兴趣,下面的序列号(升序和降序)<​​/ p>

protected static void ASC(int[]a, int left, int right, int div)
{
    int len = 1 + right - left;
    if (len < 27)
    {
        // insertion sort for small array
        int P1 = left + 1;
        int P2 = left;
        while ( P1 <= right )
        {
            div = a[P1];
            while(( P2 >= left )&&( a[P2] > div ))
            {
                a[P2 + 1] = a[P2];
                P2--;
            }
            a[P2 + 1] = div;
            P2 = P1;
            P1++;
        }
        return;
    }
    int third = len / div;
    // "medians"
    int P1 = left + third;
    int P2 = right - third;
    if (P1 <= left)
    {
        P1 = left + 1;
    }
    if (P2 >= right)
    {
        P2 = right - 1;
    }
    int temp;
    if (a[P1] < a[P2])
    {
        temp = a[P1]; a[P1] = a[left]; a[left] = temp;
        temp = a[P2]; a[P2] = a[right]; a[right] = temp;
    }
    else
    {
        temp = a[P1];  a[P1] = a[right];  a[right] = temp;
        temp = a[P2];  a[P2] = a[left];  a[left] = temp;
    }
    // pivots
    int pivot1 = a[left];
    int pivot2 = a[right];
    // pointers
    int less = left + 1;
    int great = right - 1;
    // sorting
    for (int k = less; k <= great; k++)
    {
        if (a[k] < pivot1)
        {
            temp = a[k];  a[k] = a[less];  a[less] = temp;
            less++;
        }
        else if (a[k] > pivot2)
        {
            while (k < great && a[great] > pivot2)
            {
                great--;
            }
            temp = a[k];  a[k] = a[great];  a[great] = temp;
            great--;
            if (a[k] < pivot1)
            {
                temp = a[k];  a[k] = a[less];  a[less] = temp;
                less++;
            }
        }
    }
    int dist = great - less;
    if (dist < 13)
    {
        div++;
    }
    temp = a[less-1];  a[less-1] = a[left];  a[left] = temp;
    temp = a[great+1];  a[great+1] = a[right];  a[right] = temp;
    // subarrays
    ASC(a, left, less - 2, div);
    ASC(a, great + 2, right, div);
    // equal elements
    if (dist > len - 13 && pivot1 != pivot2)
    {
        for (int k = less; k <= great; k++)
        {
            if (a[k] == pivot1)
            {
                temp = a[k];  a[k] = a[less];  a[less] = temp;
                less++;
            }
            else if (a[k] == pivot2)
            {
                temp = a[k];  a[k] = a[great];  a[great] = temp;
                great--;
                if (a[k] == pivot1)
                {
                    temp = a[k];  a[k] = a[less];  a[less] = temp;
                    less++;
                }
            }
        }
    }
    // subarray
    if (pivot1 < pivot2)
    {
        ASC(a, less, great, div);
    }
}

protected static void DSC(int[]a, int left, int right, int div)
{
    int len = 1 + right - left;
    if (len < 27)
    {
        // insertion sort for large array
        int P1 = left + 1;
        int P2 = left;
        while ( P1 <= right )
        {
            div = a[P1];
            while(( P2 >= left )&&( a[P2] < div ))
            {
                a[P2 + 1] = a[P2];
                P2--;
            }
            a[P2 + 1] = div;
            P2 = P1;
            P1++;
        }
        return;
    }
    int third = len / div;
    // "medians"
    int P1 = left + third;
    int P2 = right - third;
    if (P1 >= left)
    {
        P1 = left + 1;
    }
    if (P2 <= right)
    {
        P2 = right - 1;
    }
    int temp;
    if (a[P1] > a[P2])
    {
        temp = a[P1]; a[P1] = a[left]; a[left] = temp;
        temp = a[P2]; a[P2] = a[right]; a[right] = temp;
    }
    else
    {
        temp = a[P1];  a[P1] = a[right];  a[right] = temp;
        temp = a[P2];  a[P2] = a[left];  a[left] = temp;
    }
    // pivots
    int pivot1 = a[left];
    int pivot2 = a[right];
    // pointers
    int less = left + 1;
    int great = right - 1;
    // sorting
    for (int k = less; k <= great; k++)
    {
        if (a[k] > pivot1)
        {
            temp = a[k];  a[k] = a[less];  a[less] = temp;
            less++;
        }
        else if (a[k] < pivot2)
        {
            while (k < great && a[great] < pivot2)
            {
                great--;
            }
            temp = a[k];  a[k] = a[great];  a[great] = temp;
            great--;
            if (a[k] > pivot1)
            {
                temp = a[k];  a[k] = a[less];  a[less] = temp;
                less++;
            }
        }
    }
    int dist = great - less;
    if (dist < 13)
    {
        div++;
    }
    temp = a[less-1];  a[less-1] = a[left];  a[left] = temp;
    temp = a[great+1];  a[great+1] = a[right];  a[right] = temp;
    // subarrays
    DSC(a, left, less - 2, div);
    DSC(a, great + 2, right, div);
    // equal elements
    if (dist > len - 13 && pivot1 != pivot2)
    {
        for (int k = less; k <= great; k++)
        {
            if (a[k] == pivot1)
            {
                temp = a[k];  a[k] = a[less];  a[less] = temp;
                less++;
            }
            else if (a[k] == pivot2)
            {
                temp = a[k];  a[k] = a[great];  a[great] = temp;
                great--;
                if (a[k] == pivot1)
                {
                    temp = a[k];  a[k] = a[less];  a[less] = temp;
                    less++;
                }
            }
        }
    }
    // subarray
    if (pivot1 > pivot2)
    {
        DSC(a, less, great, div);
    }
}