精华内容
下载资源
问答
  • 大数据 | 大数据基础--算法之并行计算算法:排序算法
    千次阅读
    2020-12-07 11:57:57

    亲爱的读者朋友大家晚上好,上次我们简单介绍了并行算法以及有关矩阵乘法的几个基本问题,这次我们来分析基于MapReduce的排序算法。详见:http://bbit.vip/service/main.php?version=1&type=article&id=126

    更多相关内容
  • 4、快速排序算法并行化 5、描述了使用2m个处理器完成对n个输入数据排序的并行算法。 6、在最优的情况下并行算法形成一个高度为logn的排序树 7、完成快速排序的并行实现的流程图 8、完成快速排序的并行算法的实现
  • 并行计算mpi奇偶排序

    2018-12-16 15:45:43
    运用mpi实现奇偶排序,在不同的处理器之间通过消息传递完成奇偶index的数的交换,实现最终的数列排序
  • 并行计算实验快速排序的mpi并行实现以及omp并行实现
  • 现在假定我们使用256位并行计算,那么一次就可以处理8个整数。我们把输入的数据分成8列(如果模8有余数,先用其它算法计算出最后几个-7个之内-最大的数的排序),然后8列各自并行进行选择排序(选出最小的放在前面)...

     选择排序虽然不是效率最高的排序算法,但是它是一种比较容易并行化的排序算法。

    比如我们使用AVX2指令集(C#中以Vector<T>形式以及相关操作存在),就可以一次处理多个数据。现在假定我们使用256位并行计算,那么一次就可以处理8个整数。我们把输入的数据分成8列(如果模8有余数,先用其它算法计算出最后几个-7个之内-最大的数的排序),然后8列各自并行进行选择排序(选出最小的放在前面),最后对8列排序加以归并,这就可以实现基于SIMD的并行选择排序算法。这个并行排序算法的效率显然比串行高得多。具体实测情况,请参阅:

    GitHub - yyl-20020115/DoubleSelectionSort: The improved selection sort algorithm

    核心代码如下所示

    
    /// <summary>
    /// FastSingleSelectionSort
    /// </summary>
    int[] FastSingleSelectionSort(int[] data)
    {
        int width = Vector<int>.Count;
        int N = data.Length;
        int R = N % width;
        if (R > 0) //Sort tail
        {
            int T = N - R;
            for(int i = N-1; i >= T; i--)
            {
                int maxIndex = i;
                int max = data[maxIndex];
                for(int j = i - 1; i >= 0; j--)
                {
                    if (data[j] > max)
                    {
                        max=data[j];
                        maxIndex = j;
                    }
                }
                if (maxIndex != i)
                {
                    Swap(data, maxIndex, i);
                }
            }
            N = T;
        }
    
        int[] buffer = new int[width];
        int[] positions = new int[width];
    
        for (int i = 0; i < N - width; i+= width)
        {
            for (int q = 0; q < width; q++)
            {
                positions[q] = i + q;
            }
            var min = new Vector<int>(data,i);        
    
            for (int j = i + width; j < N; j+=width)
            {
                min.CopyTo(buffer);
                var dt = new Vector<int>(data, j);
                var rt = Vector.LessThan(dt, min);
                var any = false;
                for(int s = 0; s < width; s++)
                {
                    if (rt[s] != 0)
                    {
                        positions[s] = j + s;
                        buffer[s] = dt[s];
                        any = true;
                    }
                }
                if (any)
                {
                    min = new Vector<int>(buffer);
                }
            }
            for(int q = 0; q < width; q++)
            {
                int a = positions[q];
                int b = i + q;
                if (a != b)
                {
                    Swap(data, a, b);
                }
            }
        }
    
        return DoCollect(data, width, true);
    }
    
    void Swap(int[] a, int i, int j)
    {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    int[] DoCollect(int[] data, int width, bool copy_tail)
    {
        if (width <= 1) return data;
    
        int N = data.Length;
        int R = N % width;
        int[] positions = new int[width];
        int[] result = new int[N];
        if (copy_tail && R > 0)
        {
            Array.Copy(data, N - R, result, N - R, R);
        }
        for (int i = 0; i < width; i++)
        {
            positions[i] = i;
        }
        int p = 0;
        while (p < N)
        {
            int? minpos = null;
            int? minval = null;
            for (int i = 0; i < width; i++)
            {
                int index = positions[i];
                if (index >= data.Length) continue;
                int value = data[index];
                if (minval == null || value < minval)
                {
                    minval = value;
                    minpos = i;
                }
            }
            if (minpos is int _minpos && minval is int _minval)
            {
                positions[_minpos] += width;
                result[p++] = _minval;
            }
        }
        return result;
    }
    

    展开全文
  • 双调排序是data-independent的排序, 即比较顺序与数据无关的排序方法, 特别适合做并行计算,例如用GPU、fpga来计算。 1、双调序列 在了解双调排序算法之前,我们先来看看什么是双调序列。 双调序列是一个先单调...

    双调排序是data-independent的排序, 即比较顺序与数据无关的排序方法, 特别适合做并行计算,例如用GPU、fpga来计算。

    1、双调序列

    在了解双调排序算法之前,我们先来看看什么是双调序列。 双调序列是一个先单调递增后单调递减(或者先单调递减后单调递增)的序列。

    2、Batcher定理

    将任意一个长为2n的双调序列A分为等长的两半X和Y,将X中的元素与Y中的元素一一按原序比较,即a[i]与a[i+n] (i < n)比较,将较大者放入MAX序列,较小者放入MIN序列。则得到的MAX和MIN序列仍然是双调序列,并且MAX序列中的任意一个元素不小于MIN序列中的任意一个元素[2]。

    3、双调排序

    假设我们有一个双调序列,则我们根据Batcher定理,将该序列划分成2个双调序列,然后继续对每个双调序列递归划分,得到更短的双调序列,直到得到的子序列长度为1为止。这时的输出序列按单调递增顺序排列。

    见下图:升序排序,具体方法是,把一个序列(1…n)对半分,假设n=2^k,然后1和n/2+1比较,小的放上,接下来2和n/2+2比较,小的放上,以此类推;然后看成两个(n/2)长度的序列,因为他们都是双调序列,所以可以重复上面的过程;总共重复k轮,即最后一轮已经是长度是2的序列比较了,就可得到最终的排序结果。

    双调排序示意图[1]:

    4、任意序列生成双调序列

    前面讲了一个双调序列如何排序,那么任意序列如何变成一个双调序列呢?

    这个过程叫Bitonic merge, 实际上也是divide and conquer的思路。 和前面sort的思路正相反, 是一个bottom up的过程——将两个相邻的,单调性相反的单调序列看作一个双调序列, 每次将这两个相邻的,单调性相反的单调序列merge生成一个新的双调序列, 然后排序(同3、双调排序)。 这样只要每次两个相邻长度为n的序列的单调性相反, 就可以通过连接得到一个长度为2n的双调序列,然后对这个2n的序列进行一次双调排序变成有序,然后在把两个相邻的2n序列合并(在排序的时候第一个升序,第二个降序)。 n开始为1, 每次翻倍,直到等于数组长度, 最后就只需要再一遍单方向(单调性)排序了。以16个元素的array为例,

    1. 相邻两个元素合并形成8个单调性相反的单调序列,
    2. 两两序列合并,形成4个双调序列,分别按相反单调性排序
    3. 4个长度为4的相反单调性单调序列,相邻两个合并,生成两个长度为8的双调序列,分别排序
    4. 2个长度为8的相反单调性单调序列,相邻两个合并,生成1个长度为16的双调序列,排序

    示意图[1]:

    详细Bitonic merge图(本图只画到生成一个16长的双调序列,最后排序没有画出):

    最后再放一个8个元素排序的示意图[5]:

    5、非2的幂次长度序列排序

    这样的双调排序算法只能应付长度为2的幂的数组。那如何转化为能针对任意长度的数组呢?一个直观的方法就是使用padding。即使用一个定义的最大或者最小者来填充数组,让数组的大小填充到2的幂长度,再进行排序。最后过滤掉那些最大(最小)值即可。这种方式会使用到额外的空间,而且有时候padding的空间比较大(如数组长度为1025个元素,则需要填充到2048个,浪费了大量空间)。但是这种方法比较容易转化为针对GPU的并行算法。所以一般来说,并行计算中常使用双调排序来对一些较小的数组进行排序[3]。 如果要考虑不用padding,用更复杂的处理方法,参考[4] n!=2^k的双调排序网络,本文略。

     

     

    参考资料

    [1] CUDA(六). 从并行排序方法理解并行化思维——冒泡、归并、双调排序的GPU实现, http://blog.csdn.net/abcjennifer/article/details/47110991

    [2] 并行计算】Bitonic Sort(双调排序)基础, http://blog.csdn.net/jiange_zh/article/details/49533477

    [3] 双调排序:从串行到并行,以及OpenCL上的实现, http://blog.csdn.net/bryanlai0720/article/details/45094675

    [4] n!=2^k的双调排序网络, http://blog.csdn.net/ljiabin/article/details/8630627

    [5] 分段双调排序实现, http://blog.csdn.net/u014226072/article/details/56840243

     

    原文地址: https://blog.csdn.net/xbinworld/article/details/76408595

    展开全文
  • 最近老师讲了并行的排序算法,让我对这个原来不是很了解的排序算法产生了浓厚的兴趣。并行排序方法,是指采用并行计算的方法对一组数据进行排序,理论上是在类似内排序的环境下,采用多核并行的方法让时间降低,排序...

    最近老师讲了并行的排序算法,让我对这个原来不是很了解的排序算法产生了浓厚的兴趣。并行排序方法,是指采用并行计算的方法对一组数据进行排序,理论上是在类似内排序的环境下,采用多核并行的方法让时间降低,排序的复杂度最好的情况下能降低至O(n)左右。

    排序的实质

    排序的实质是什么?这是一个不是问题的问题。我们可以说是让所有的数都按照一定的规则被放置,但这种说法实际上是解释了排序的汉字含义。换句话不如说排序是:从序列中任选一对数都是有序的,那么此序列就是已排序的

    普通(串行)冒泡排序

    为了满足上述的概念,我们发现了冒泡排序法双层循环,比较数组中可取到的任意一对数字,如果不满足要求则交换。这是一种最简单的排序方法,理解起来很简单,也与上述的排序实质含义很符合。但是我们在平常的程序中完全不会采用冒泡排序,这是因为冒泡排序有很多缺点:

    1. 比较次数是所有排序中最多的,必须要进行(n-1)2/2次比较,按照冒泡排序的定义,很难有优化的方法。
    2. 交换次数不固定而且很多,相比较冒泡排序的次数不固定,同样是复杂度为O(n2)的选择排序虽然比较次数也较多,但是可以把交换次数稳定在n次。
    3. 不能利用序列一些隐含的信息。冒泡排序只能不断的比较比较比较,对序列没有记忆性,相比较冒泡排序同样是复杂度为O(n2)的插入排序和复杂度约为O(n1.3)的希尔排序却能在序列为几乎完成排序的状态下用相当好的效果完成排序。

    冒泡排序、选择排序和插入排序同为O(n2)简单排序,但是相比较另外两种还有一些特点,冒泡排序基本没什么用算是废了。

    package Main;
    
    /**
     * Title: BubbleSort
     * Description: BubbleSort Test
     * Company: www.QuinnNorris.com
     *
     * @date: 2017/11/30 上午12:31 星期四
     * @author: quinn_norris
     * @version: 1.0
     */
    public class BubbleSort {
    
        public static void main(String[] args) {
            int[] arr = {3, 2, 1, 4, 5};
            bubbleSort(arr);
        }
    
        public static int[] bubbleSort(int[] arr) {
            int n = arr.length;
            for (int i = 0; i < n - 1; i++)
                for (int j = 0; j < n - 1 - i; j++)
                    if (arr[j] > arr[j + 1]) {
                        arr[j] = arr[j] ^ arr[j + 1];
                        arr[j + 1] = arr[j] ^ arr[j + 1];
                        arr[j] = arr[j] ^ arr[j + 1];
                    }
            return arr;
        }
    
    }

    冒泡排序推广——奇偶交换排序

    就像是红黑树的结构推广自比较简单的2-3树一样,这里用刚才的冒泡排序推广出另外一种较为复杂的排序:奇偶交换排序。

    在冒泡排序中,我们采用的思想是不断的比较临近的两个数字,如果位置不对就交换。在每轮中一个数字可能会与身边的另一个发生交换,理论上至多需要n轮才能把一个数字确保交换到正确的位置上。第一次循环会讲最大的数字移动到数组最右边,下一次循环把第二大的数移动到右侧第二个位置,以此类推。而奇偶交换排序是将每一轮每对数字比较与交换操作分为奇偶两类分别执行。

    比如一种可行的情况,当n=3时:

    1. 先进行偶数比较并交换 arr[0],arr[1]
    2. 再进行奇数比较并交换 arr[1],arr[2]
    3. 再进行偶数比较并交换 arr[0],arr[1]

    定义:奇偶交换排序进行n轮比较与交换,第一轮进行所有索引为偶数的元素与后一位进行比较(如果没有后一位则不进行比较),如果顺序有误则交换;下一轮进行所有索引为奇数的元素与后一位比较(如果没有后一位则不进行比较),如果顺序有误则交换;如此反复交替进行n轮,则此时序列为已排序序列。

    奇偶交换排序正确性验证

    一般的,有如下定理:

    设A是一个拥有n个键值的列表,作为奇偶交换排序算法的输入,那么经过n个阶段后,A能够排好序。

    尝试了一下,当n为3的时候将{3,2,1}序列转化为{1,2,3}序列需要3步,当n为5的时候将{5,4,3,2,1}序列转化为{1,2,3,4,5}序列需要5步都满足上述定理。但是这只是特例尝试,能不能用一般性证明上述定理的正确性呢?个人觉得大概可以采用如下思路证明:

    当n=5时,
    第一次: 先进行偶数比较并交换 (arr[0],arr[1]) (arr[2],arr[3])
    第二次: 再进行奇数比较并交换 (arr[1],arr[2]) (arr[3],arr[4])
    第三次: 再进行偶数比较并交换 (arr[0],arr[1]) (arr[2],arr[3])
    第四次: 再进行奇数比较并交换 (arr[1],arr[2]) (arr[3],arr[4])
    第五次: 再进行偶数比较并交换 (arr[0],arr[1]) (arr[2],arr[3])

    直接看很难看出这种方法的正确性,我们稍微做一些变换,将一次偶数的交换和奇数的交换的效果联合起来形成一条交换链。比如上例n=5时,从n=0开始或n=1开始向下取四次交换都可以形成两条完成的交换链,总计能够形成n/2条交换链,每条交换链相当于冒泡排序中一次完整的比较,在一条交换链中一个元素可以移动0个位置、1个位置或2个位置,在n/2条交换链中一个元素最多可移动n/2*2=n个位置,通过交换链这种说法我们得出结论,任何一个元素可以移动到序列中任何想要的位置上

    回忆未优化的冒泡排序,冒泡排序的正确性是显而易见的,在冒泡排序中一个元素被比较的次数最多为n次,而在奇偶交换排序中每个中间元素被比较的次数也为n次,在奇数次与一侧数据比较,偶数次与另侧数据比较,不断交替这两种情况。由此我们可以将奇偶交换排序转化为元素比较方向不断变化的冒泡排序。只要证明比较方向不断变化的冒泡排序是正确的即可,它的正确性是显然的。

    运用奇偶交换排序算法进行并行排序

    在不使用并行的时候,奇偶交换排序的复杂度为每轮的比较次数乘以比较轮数O(n2)。但是如果我们用多核去并行计算那么它的时间复杂度就能降到约O(n)左右。

    n个数据使用n核计算

    如果我们一共有n个数据需要进行排序,那么我们使用n个核,每个核存储一个数据。当进行外循环时,如果外轮的索引是偶数,那么就控制内层的偶数索引的核和它左侧的奇数索引的核的数据进行比较如果顺序有误则交换,当外循环索引是奇数,那么相反和右侧的进行比较交换。这样,内层循环采用并行的方法,时间复杂度为O(1),整体复杂度为O(n),在较短的时间内仍能保证算法的正确性。

    n个数据使用p核计算

    上面的例子是在n个数据使用n核计算的情况下,但是实际上根本不可能出现这种情况,一般的我们的数据都非常大,而我们能够使用的核数最多在两位数,那么在这种情况下,我们为每个核分配n/p个数据,首先将每个核内进行快速的内排序,然后在每个核之间进行类似奇偶交换排序的算法进行排序,只不过这时两个核中的数据不能简单比较,我们在这里采用归并排序的方法对两个核中的数据进行排序,然后把小的那一半放在左边,大的另外一半数据放在右边。用这种方法模拟出奇偶交换排序的思路。当p越大时、当p和n越接近时这种算法效率最好,这种情况下时间复杂度与p有关,但因为采用的这种方法本身原因,算法复杂度必定要小过O(nlogn),是一种不错的并行排序方法。

    为什么用冒泡进行并行排序而不用其他排序算法?

    为什么采用冒泡算法的变种奇偶排序算法进行并行排序,而不采用其他的选择、插入、快速、堆、归并等等…其他的算法进行并行排序呢?

    原因在于奇偶交换排序有个优点,在每一轮内部,他的比较和交换是同时发生的可以同时处理。就是说在每一轮内部,两个数字间如果比较后发现顺序错误那么这两个数据交换即可,这两个数字的状态和本轮内其他任何数字都没有关系,是独立的。在多核中,每一组配对的核只需要判断对方的情况并选择是否进行交换即可,这些组可以同时进行没有依赖关系。

    观察其他的排序算法,选择排序是在一轮中挑选出最大的数字交换位置,无论是否用多核计算,必定有n次的遍历;插入排序要一直判断与前一个数字相比的大小也是必定有n次遍历;而快速排序和归并排序将数据分组递归计算这不适合用并行计算;堆排序先进行线性时间的建堆,再不断调整树结构进行排序时间较大的部分在调整树结构,但这部分根本没办法用并行去优化。

    展开全文
  • 并行实验报告一、项目背景项目要求实现快速排序、枚举排序、归并排序三种排序方法的串行和并行算法,并且进行性能比较和优化分析。其中数据集`random.txt`,当中包含30000个乱序数据,数据的范围是[-50000,50000],...
  • 不一样的排序算法并行排序】

    千次阅读 2018-03-15 20:24:24
    比如冒泡排序,插入排序,选择排序,堆排序等等,但是随着计算机的发展,现在的计算机都是多核的处理器,串行排序无法高效的利用CPU,为了更加有效的利用CPU,我们在这里介绍一下在并行世界中的排序算法。...
  • 基于openMP的并行计数排序算法

    千次阅读 2020-04-21 15:05:56
    基于openMP的并行计数排序算法 这是云计算的作业,实现对某个算法或程序的性能优化,以前没有接触过,所以使用了比较简单上手的openMP来实现。 代码如下 #include <stdio.h> #include <omp.h> #include ...
  • Java Fork/Join框架 Fork/Join框架是一种能够并行执行任务...使用Fork/Join框架进行并行计算不仅简单高效而且具有良好的并行性能,Fork/Join并行算法的核心是分治算法的并行实现。 如图1-2所示,其中:fork操作...
  • MPI和openMP并行计算-冒泡排序
  • 并行计算课程实验代码,c语言写的,在MacOS系统下的openmp的pi值计算和PSRS的实现,注释清晰,且PSRS处理了不整除的情况。懒得编译可使用我提供的run.sh脚本。加上待编译的文件作为参数即可。
  • 值得一提的是,奇偶排序算法设计的初衷便是并行计算,只是更加贴合OpenMP这种共享内存式的编程框架,以后会和大家分享。 3.MPI模式下的奇偶排序算法,有更大的灵活性(个人观点:用到了奇偶排序的思想,并不是完全...
  • 快速排序并行运算,
  • 本文主要讨论并行排序算法的实现,将串行的奇偶排序算法并行化。同时本文也涉及MPI通信安全方面的讨论,MPI_SendRecv函数提供了有关进程通信的调度,用它替代send和recv函数使程序更安全
  • 冒泡排序并行计算

    千次阅读 2020-01-04 16:15:43
    今天做了一下冒泡排序并行计算比较: 串行冒泡排序如下: #include <stdio.h> #include <stdlib.h> #include <windows.h> void BubbleSort(int * pData, int nSize) { if (!pData) { ....
  • 1.双调序列 假设序列A是一个单调递增序列,B是一个单调di'j递减序列,... 参考文献 : 【1】三十分钟理解:双调排序Bitonic Sort,适合并行计算排序算法 https://blog.csdn.net/xbinworld/article/details/76408595
  • 使用MPI计算的完整的PSRS(并行排序(parallel sorting by regular sampling))代码。并行计算课实验所用代码。
  • 双调排序是data-independent的排序, 即比较顺序与数据无关的排序方法, 特别适合做并行计算,例如用GPU、fpga来计算。
  • 9.6 其他排序算法 9.6.1 枚举排序 9.6.2 基数排序 9.7 书目评注 习题 第10章 图算法 10.1 定义和表示 10.2 最小生成树:Prim算法 10.3 单源最短路径:Dijkstra算法 10.4 全部顶点对间的最短路径 10.4.1 ...
  • 4、快速排序算法并行化 5、描述了使用2m个处理器完成对n个输入数据排序的并行算法。 6、在最优的情况下并行算法形成一个高度为logn的排序树 7、完成快速排序的并行实现的流程图 8、完成快速排序的并行算法的实现
  • 呜~ 就隔了一段时间没看并行计算,发现作业贼难顶,不得不写篇博客来记录一下复习(预习)的内容。 并行计算性能评测 并行机的一些基本性能指标 对并行计算机的性能关注点还是落在了CPU和存储器上,毕竟CPU和存储器...
  • 枚举排序是一种最简单的排序算法,该算法的具体思想是对每一个待排序的元素统计小于它的所有元素的个数,从而得到该元素最终处于序列钟的位置。对该算法的并行化是很简单的,假设对一个长为n的输入序列使用n个处理器...
  • 整理最全资料:并行计算大作业:矩阵乘法,排序算法,代码+课件+报告超详细
  • 并行计算排序中,每个处理器对应处理一个值,并仅有与左右邻居的本地互连。所有处理器可同时与邻居进行比较、交换操作,交替以奇-偶、偶-奇的顺序。该算法由Habermann在1972年最初发表并展现了在并行
  • 并行计算及并行算法

    万次阅读 多人点赞 2018-06-13 22:27:31
    一、并行计算  简单地说,并行计算就是在并行计算机上所做的计算。从普通意义上讲,它和常说的高性能计算、超级计算等是同义词。并行计算的初衷是为了努力仿真自然世界中一个序列中含有众多同时发生的、复杂且相关...
  • 快速排序并行算法

    2012-05-17 12:48:45
    快速排序的并行实现,提高效率。快速排序算法并行化的一个简单思想是,对每次划分过后所得到的两个序列分别使用两个处理器完成递归排序。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 73,692
精华内容 29,476
热门标签
关键字:

并行计算排序算法