经典排序算法以及负载平衡下的平行归并排序Parallel Merge Sort with Load Balancing

常见经典排序算法有:冒泡排序,快速排序,插入排序,选择排序,归并排序、希尔排序。
冒泡排序就不介绍了,首先是快速排序QuickSort:
过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

如数据为  6   2   7  3  8  9
first:
furst -1
first -a:3 2 7 6 8 9(从后往前,找比6(第一个数据)小的数交换)
first -b:3 2 6 7 8 9(再从前往后(从2开始),找比6大的数据
first...一次按first-1来先找比6小,再找比6大,直至结束。
first-result3 2 6 7 8 9
second:
以 6为界限,划分两部分 得 3 27 8 9
先计算 3 2参照first;
再 7 8 9,同样操作。

插入即表示将一个新的数据插入到一个有序数组中,并继续保持有序。

从第二个数字开始,假设前面的已经排好序,该数为带插入前面有序的数字中,接着第三个,插入到前面序列
好了,快排就是这样的,下面是插入排序

5060,71,49,11,24,3,66  k=60(2)

50,6071,4911,24,66
next 插入
k=71(3)
50,6071,49,11,24,3,66)
k=49(4)(下一个)
50,60,49,71,11,24,3,69
50,49,60,71,..
49,50,60,71,11,24,3
k=11(第五个数)
...
...

选择排序

每次找出最小数,从i=1 to n
example 3(start) 5 1 2 7 6
i=0,从j=1 to n找最小到第一个交换
1 5(start)  3 2 7 6
1 2 3 5 7 6
....

希尔排序

```
           9 1 2 5 7 4 8 6 3 6
first组合: 9         4 (比较交换)
             1         8
               2         6
                 5         3
                   7         6
组合(9[index1] 4[index[5]),(1[2],8[6]),(2[3],6[7]),...
排好序列归位:
           4 1 2 3 6 9 8 6 5 7
再组合:    4   2   6   8   5
             1   3   9   6   7
             排序归位
             ...            
           that's all!

归并排序,简单来说就是分治法,分治法被广泛用于大数据,云计算中,比如hadoop的mapreduce很大一部分来源于此。14年本人看的第一篇论文就是并行归并排序算法,附上理解
Title:Parallel Merge Sort with Load Balancing
作者:Minsoo Jeon and Dongseung Kim
传统的并行归并排序介绍:
分解:将原问题分解成一系列子问题
解决:递归的解决各子问题
合并:将子问题的解合并成原问题的解
算法思想:
1.将N个数据(平)分给P个处理器
2.P个处理器对每一组数据进行排序
3.把每两个处理器排好的序列合并再排序,此时处于工作状态的处理器数量减半
4.重复第3步,直到只剩下最后一个处理器处理所有数据,排序完毕。

begin
h :=P
1. forall 0 [ i [ P−1
     Pi sorts a list of N/P keys locally.
2. for j=0 to (log P)−1 do
        forall 0 [ i [ h−1
           if (i < h/2) then
              2.1. Pi receives N/h keys from Pi+h/2
              2.2. Pi merges two lists of N/h keys into a sorted list of 2N/h
          else
          2.3. Pi sends its list to Pi−h/2
      h :=h/2
end

/*
P:处理器数量
Pi:第i个处理器
h:处于工作状态的处理器数量

*/

传统平行归并算法算法示意图:

这里写图片描述

for example:

原始数据:14,1,18,2,16,4,7,21
STEP1:分给两个处理器P0和P1:
P0:14,1,18,2                             P1:16,4,7,21
     Step2:P0和P1对两组数据做快速排序:
P0:1, 2, 14,   18                               P1:4,7,16,21
     Step3:将P0里的最小数与P1的最小数比较,P0里1比P1里的4小,然后进行下一步,继续将P0的第二个数与P1的4比较,将P1的最小数在P0里做插入排序,P1插入到P0的2和14之间,此时有:
 P0:1,2,4,14,18                               P1:7,16,21
     Step4:将P1的7从P0的4往后插入排序,以此递归,最后
    P0:1,2,4,7,14,16,18,21
   排序完毕,P1为空。      

code:

/*p[i]为第i块处理器,建议开启多线程模仿或者多处理器编程,本人只是做了实现,代码提供参考*/
#include<stdlib.h>
void sort1(int n,int a[])
{int i,j,key;
for(i=0;i<n;i++)
 for(j=i+1;j<n;j++)
    if(a[i]>a[j])
    { key=a[i];
      a[i]=a[j];
      a[j]=key;
    }
}
void sort2(int m,int a[],int b[])
{int i,j=0,k,s=m;
a[4]=65535;
b[4]=65535;
for(i=0;i<m;i++)
{ while(b[i]>a[j])
 {
 j++;
 }
 {{s++;
     for(k=s-1;k>j;k--)
         a[k]=a[k-1];

 }
 a[j]=b[i];}

}
}
void main()
{
int p[8];
int p0[8];
int p1[8];
int i;
printf("please input 8 keys:\n");
for(i=0;i<8;i++)
scanf("%d",&p[i]);
for(i=0;i<4;i++)
{p0[i]=p[i];
p1[i]=p[i+4];}
sort1(4,p0);
sort1(4,p1);
printf("\ndata in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);
sort2(5,p0,p1);
printf("\nthe data sorted stores in P0:\n");
for(i=0;i<8;i++)
printf("%d ",p0[i]);

}
 平行归并算法在处理大量数据是非常有效,但是传统的归并算法(分治法)性能很差,因为每次合并处理时,处理器就会减少一半,加重了每个处理器所处理的数据长度,合并到最后时,只有一个处理器处理所有的数据。
 相比其他快速法而言,它有利于处理大量数据,但是该传统算法越往后进行,就有越来越多的处理器处于闲置状态,因此归并排序算法必须平行化处理,才能发挥出最大优势,本文推荐了一种负载平衡下的并行归并排序算法,该算法在整个计算过程中,所有处理器均参与计算。在每一个阶段都分配数据到每一个处理器上。这样性能就大大提高。

*下面就是介绍我们强大的负载平衡下的平行归并算法~~
算法思想:
1.将N个带排序数据(平)分给P个处理器;
2.P个处理器同时对P组数据进行排序(从小到大);
3.将每两个相邻处理器做比较,将第一个处理器的最大数(最右边数)与第二个处理器的最小数(最左边数)作比较,若第一个处理器的最大数小于第二个处理器的最小数,则这两个处理器的数据排序完成,反之,则交换边界数,两处理器又再次重新排序;
4.依次做递归,直到这两组数据完全排序完成;
5.这时P个处理器在使用,待排序数组变成P/2个数组;
6.依次递归进行归并,把待排序数组归并,处理器并行适应,每次待排序数组减半,直到结束为止。*
这里写图片描述

输入原始数据:15,6,56,78,1,3,99,2
Step1:将数据平分给P0P1
P0:15,6,56,78                P1:1,3,99,2
Step2:P0,P1两组处理器分别对两组数排序,拍完后:
P0:6,15,56,78                P1:1,2,3,99
Step3:比较P0中最右边数(最大数)与P1最左边数(最小数),若P0最大数小于P1最小数,则排序完成,反之,交换两边界数
Step4:交换后
P0:6,15,56,1         P1:78,2,3,99
Step5:重复Step2,Step3,Step4,直到结束,得到
P0:1,2,3,6             P1:15,56,78,99
排序完毕,P0中数小于P1中数

Here is the code:

#include<stdlib.h>
void sort1(int n,int a[])
{int i,j,key;
for(i=0;i<n;i++)
 for(j=i+1;j<n;j++)
    if(a[i]>a[j])
    { key=a[i];
      a[i]=a[j];
      a[j]=key;
    }
}
void main()
{
int p[8];
int p0[4];
int p1[4];
int i,data1;
printf("please input 8 keys:\n");
for(i=0;i<8;i++)
scanf("%d",&p[i]);
for(i=0;i<4;i++)
{p0[i]=p[i];
p1[i]=p[i+4];}
sort1(4,p0);
sort1(4,p1);
printf("data in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);
while(p0[3]>p1[0]){
   data1=p0[3];
   p0[3]=p1[0];
   p1[0]=data1;
   printf("\ndata in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);
sort1(4,p0);
sort1(4,p1);
 printf("\ndata in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);


}
printf("\nthe data sorted stores in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\nthe data sorted stores in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);

}
/*p[i]同样是模拟第i块处理器

*/

for example:

输入原始数据:15,6,56,78,1,3,99,2
Step1:将数据平分给P0P1
P0:15,6,56,78                P1:1,3,99,2
Step2:P0,P1两组处理器分别对两组数排序,拍完后:
P0:6,15,56,78                P1:1,2,3,99
Step3:比较P0中最右边数(最大数)与P1最左边数(最小数),若P0最大数小于P1最小数,则排序完成,反之,交换两边界数
Step4:交换后
P0:6,15,56,1         P1:78,2,3,99
Step5:重复Step2,Step3,Step4,直到结束,得到
P0:1,2,3,6             P1:15,56,78,99
排序完毕,P0中数小于P1中数

该算法经常用于分布式文件系统‘大数据处理,并行高性能计算。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,归并排序是一种经典排序算法,它的时间复杂度为 O(nlogn)。而 OpenMP 是一种并行编程的技术,可以用来加速归并排序的执行。下面是一个使用 OpenMP 实现的归并排序的示例代码: ```c++ #include <omp.h> #include <stdio.h> #include <stdlib.h> void merge(int *arr, int l, int m, int r) { int i, j, k; int n1 = m - l + 1; int n2 = r - m; int *L = (int*) malloc(n1 * sizeof(int)); int *R = (int*) malloc(n2 * sizeof(int)); for (i = 0; i < n1; i++) L[i] = arr[l + i]; for (j = 0; j < n2; j++) R[j] = arr[m + 1 + j]; i = 0; j = 0; k = l; while (i < n1 && j < n2) { if (L[i] <= R[j]) { arr[k] = L[i]; i++; } else { arr[k] = R[j]; j++; } k++; } while (i < n1) { arr[k] = L[i]; i++; k++; } while (j < n2) { arr[k] = R[j]; j++; k++; } free(L); free(R); } void merge_sort(int *arr, int l, int r) { if (l < r) { int m = l + (r - l) / 2; #pragma omp parallel sections { #pragma omp section { merge_sort(arr, l, m); } #pragma omp section { merge_sort(arr, m + 1, r); } } merge(arr, l, m, r); } } int main() { int arr[] = { 12, 11, 13, 5, 6, 7 }; int n = sizeof(arr) / sizeof(arr[0]); printf("Given array is \n"); for (int i = 0; i < n; i++) printf("%d ", arr[i]); merge_sort(arr, 0, n - 1); printf("\nSorted array is \n"); for (int i = 0; i < n; i++) printf("%d ", arr[i]); return 0; } ``` 在上面的代码中,我们使用了 `#pragma omp parallel sections` 来并行执行归并排序的左半部分和右半部分。这样可以加速归并排序的执行,从而提高算法的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值