并行计算实验快速排序的并行算法.docx
- 文档编号:28009576
- 上传时间:2023-07-07
- 格式:DOCX
- 页数:23
- 大小:200.53KB
并行计算实验快速排序的并行算法.docx
《并行计算实验快速排序的并行算法.docx》由会员分享,可在线阅读,更多相关《并行计算实验快速排序的并行算法.docx(23页珍藏版)》请在冰豆网上搜索。
并行计算实验快速排序的并行算法
3.1实验目的与要求
1、熟悉快速排序的串行算法
2、熟悉快速排序的并行算法
3、实现快速排序的并行算法
3.2实验环境及软件
单台或联网的多台PC机,Linux操作系统,MPI系统。
3.3实验内容
1、快速排序的基本思想
2、单处理机上快速排序算法
3、快速排序算法的性能
4、快速排序算法并行化
5、描述了使用2m个处理器完成对n个输入数据排序的并行算法。
6、在最优的情况下并行算法形成一个高度为logn的排序树
7、完成快速排序的并行实现的流程图
8、完成快速排序的并行算法的实现
3.4实验步骤
3.4.1、快速排序(QuickSort)是一种最基本的排序算法,它的基本思想是:
在当前无序区R[1,n]中取一个记录作为比较的“基准”(一般取第一个、最后一个或中间位置的元素),用此基准将当前的无序区R[1,n]划分成左右两个无序的子区R[1,i-1]和R[i,n](1≤i≤n),且左边的无序子区中记录的所有关键字均小于等于基准的关键字,右边的无序子区中记录的所有关键字均大于等于基准的关键字;当R[1,i-1]和R[i,n]非空时,分别对它们重复上述的划分过程,直到所有的无序子区中的记录均排好序为止。
3.4.2、单处理机上快速排序算法
输入:
无序数组data[1,n]
输出:
有序数组data[1,n]
Begin
callprocedurequicksort(data,1,n)
End
procedurequicksort(data,i,j)
Begin
(1)if(i (1.1)r=partition(data,i,j) (1.2)quicksort(data,i,r-1); (1.3)quicksort(data,r+1,j); endif End procedurepartition(data,k,l) Begin (1)pivo=data[l] (2)i=k-1 (3)forj=ktol-1do ifdata[j]≤pivothen i=i+1 exchangedata[i]anddata[j] endif endfor (4)exchangedata[i+1]anddata[l] (5)returni+1 End 3.4.3、快速排序算法的性能主要决定于输入数组的划分是否均衡,而这与基准元素的选择密切相关。 在最坏的情况下,划分的结果是一边有n-1个元素,而另一边有0个元素(除去被选中的基准元素)。 如果每次递归排序中的划分都产生这种极度的不平衡,那么整个算法的复杂度将是Θ(n2)。 在最好的情况下,每次划分都使得输入数组平均分为两半,那么算法的复杂度为O(nlogn)。 在一般的情况下该算法仍能保持O(nlogn)的复杂度,只不过其具有更高的常数因子。 3.4.4、快速排序算法并行化的一个简单思想是,对每次划分过后所得到的两个序列分别使用两个处理器完成递归排序。 例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到排序好的序列。 当然这里举的是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么排序的效率会相对较差。 3.4.5、描述了使用2m个处理器完成对n个输入数据排序的并行算法。 快速排序并行算法 输入: 无序数组data[1,n],使用的处理器个数2m 输出: 有序数组data[1,n] Begin para_quicksort(data,1,n,m,0) End procedurepara_quicksort(data,i,j,m,id) Begin (1)if(j-i)≤korm=0then (1.1)Pidcallquicksort(data,i,j) else (1.2)Pid: r=patrition(data,i,j) (1.3)Pidsenddata[r+1,m-1]toPid+2m-1 (1.4)para_quicksort(data,i,r-1,m-1,id) (1.5)para_quicksort(data,r+1,j,m-1,id+2m-1) (1.6)Pid+2m-1senddata[r+1,m-1]backtoPid endif End 3.4.6、在最优的情况下该并行算法形成一个高度为logn的排序树,其计算复杂度为O(n),通信复杂度也为O(n)。 同串行算法一样,在最坏情况下其计算复杂度降为O(n2)。 正常情况下该算法的计算复杂度也为O(n),只不过具有更高的常数因子。 3.4.7、完成快速排序的并行实现的流程图 3.4.8、完成快速排序的并行算法的实现 #include #include #defineTRUE1 /* *函数名: main *功能: 实现快速排序的主程序 *输入: argc为命令行参数个数; *argv为每个命令行参数组成的字符串数组。 *输出: 返回0代表程序正常结束 */ intGetDataSize(); para_QuickSort(int*data,intstart,intend,intm,intid,intMyID); QuickSort(int*data,intstart,intend); intPartition(int*data,intstart,intend); intexp2(intnum); intlog2(intnum); ErrMsg(char*msg); main(intargc,char*argv[]) { intDataSize; int*data; /*MyID表示进程标志符;SumID表示组内进程数*/ intMyID,SumID; inti,j; intm,r; MPI_Statusstatus; /*启动MPI计算*/ MPI_Init(&argc,&argv); /*MPI_COMM_WORLD是通信子*/ /*确定自己的进程标志符MyID*/ MPI_Comm_rank(MPI_COMM_WORLD,&MyID); /*组内进程数是SumID*/ MPI_Comm_size(MPI_COMM_WORLD,&SumID); /*根处理机(MyID=0)获取必要信息,并分配各处理机进行工作*/ if(MyID==0) { /*获取待排序数组的长度*/ DataSize=GetDataSize(); data=(int*)malloc(DataSize*sizeof(int)); /*内存分配错误*/ if(data==0) ErrMsg("Mallocmemoryerror! "); /*动态生成待排序序列*/ srand(396); for(i=0;i { data[i]=(int)rand(); printf("%10d",data[i]); } printf("\n"); } m=log2(SumID);//调用函数: 求以2为底的SumID的对数 /*从根处理器将数据序列广播到其他处理器*/ /*{"1"表示传送的输入缓冲中的元素的个数,*/ /*"MPI_INT"表示输入元素的类型,*/ /*"0"表示rootprocessor的ID}*/ MPI_Bcast(&DataSize,1,MPI_INT,0,MPI_COMM_WORLD); /*ID号为0的处理器调度执行排序*/ para_QuickSort(data,0,DataSize-1,m,0,MyID); /*ID号为0的处理器打印排序完的有序序列*/ if(MyID==0) { printf("实际应用处理器数: %d\n",exp2(m-1)); for(i=0;i { printf("%10d",data[i]); } printf("\n"); } MPI_Finalize();//结束计算 return0; }/* *函数名: para_QuickSort *功能: 并行快速排序,对起止位置为start和end的序列,使用2的m次幂个处理器进行排序 *输入: 无序数组data[1,n],使用的处理器个数2^m *输出: 有序数组data[1,n] */ para_QuickSort(int*data,intstart,intend,intm,intid,intMyID) { inti,j; intr; intMyLength; int*tmp; MPI_Statusstatus; MyLength=-1; /*如果可供选择的处理器只有一个,那么由处理器id调用串行排序,对应于算法步骤(1.1)*/ /*(1.1)Pidcallquicksort(data,i,j)*/ if(m==0) { if(MyID==id) QuickSort(data,start,end); return; } /*由第id号处理器划分数据,并将后一部分数据发送到处理器id+exp2(m-1),对应于算法步骤(1.2,1.3)*/ /*(1.2)Pid: r=patrition(data,i,j)*/ if(MyID==id) { /*将当前的无序区R[1,n]划分成左右两个无序的子区R[1,i-1]和R[i,n](1≤i≤n)*/ r=Partition(data,start,end); MyLength=end-r; /*(1.3)Pidsenddata[r+1,m-1]toP(id+2m-1)*/ /*{MyLength表示发送缓冲区地址;*/ /*发送元素数目为1;*/ /*MyID是消息标签}*/ /*在下面添加一条语句发送长度*/ MPI_Send(&MyLength,1,MPI_INT,id+exp2(m-1),MyID,MPI_COMM_WORLD); /*若缓冲区不空,则第id+2m-1号处理器取数据的首址是data[r+1]*/ if(MyLength! =0) /*在下面添加一条语句*/ MPI_Send(data+r+1,MyLength,MPI_INT,id+exp2(m-1),MyID,MPI_COMM_WORLD); } /*处理器id+exp2(m-1)接受处理器id发送的消息*/ if(MyID==id+exp2(m-1)) {/*在下面添加一条语句*/ MPI_Recv(&MyLength,1,MPI_INT,id,id,MPI_COMM_WORLD,&status); if(MyLength! =0) { tmp=(int*)malloc(MyLength*sizeof(int)); if(tmp==0)ErrMsg("Mallocmemoryerror! "); /*在下面添加一条语句*/ MPI_Recv(tmp,MyLength,MPI_INT,id,id,MPI_COMM_WORLD,&status); } } /*递归调用并行排序,对应于算法步骤(1.4,1.5)*/ /*用2^m-1个处理器对start--(r-1)的数据进行递归排序*/ j=r-1-start; MPI_Bcast(&j,1,MPI_INT,id,MPI_COMM_WORLD); /*(1.4)para_quicksort(data,i,r-1,m-1,id)*/ if(j>0) /*在下面添加一条语句*/ para_QuickSort(data,start,r-1,m-1,id,MyID); /*用2^m-1个处理器对(r+1)--end的数据进行递归排序*/ j=MyLength; MPI_Bcast(&j,1,MPI_INT,id,MPI_COMM_WORLD); /*(1.5)para_quicksort(data,r+1,j,m-1,id+2m-1)*/ if(j>0) /*在下面添加一条语句*/ para_QuickSort(tmp,0,MyLength-1,m-1,id+exp2(m-1),MyID); /*将排序好的数据由处理器id+exp2(m-1)发回id号处理器,对应于算法步骤(1.6)*/ /*(1.6)P(id+2m-1)senddata[r+1,m-1]backtoPid*/ if((MyID==id+exp2(m-1))&&(MyLength! =0)) MPI_Send(tmp,MyLength,MPI_INT,id,id+exp2(m-1),MPI_COMM_WORLD); if((MyID==id)&&(MyLength! =0)) MPI_Recv(data+r+1,MyLength,MPI_INT,id+exp2(m-1),id+exp2(m-1),MPI_COMM_WORLD,&status); } /* *函数名: QuickSort *功能: 对起止位置为start和end的数组序列,进行串行快速排序。 *输入: 无序数组data[1,n] *返回: 有序数组data[1,n] */ QuickSort(int*data,intstart,intend) { intr; inti; if(start { r=Partition(data,start,end); QuickSort(data,start,r-1); QuickSort(data,r+1,end); } return0; } /* *函数名: Partition *功能: 对起止位置为start和end的数组序列,将其分成两个非空子序列, *其中前一个子序列中的任意元素小于后个子序列的元素。 *输入: 无序数组data[1,n] *返回: 两个非空子序列的分界下标 */ intPartition(int*data,intstart,intend) { intpivo; inti,j; inttmp; pivo=data[end]; i=start-1;/*i(活动指针)*/ for(j=start;j if(data[j]<=pivo) { i++;/*i表示比pivo小的元素的个数*/ tmp=data[i]; data[i]=data[j]; data[j]=tmp; } tmp=data[i+1]; data[i+1]=data[end]; data[end]=tmp;/*以pivo为分界,data[i+1]=pivo*/ returni+1; } /* *函数名: exp2 *功能: 求2的num次幂 *输入: int型数据num *返回: 2的num次幂 */ intexp2(intnum) { inti; i=1; while(num>0) { num--; i=i*2; } returni; } /* *函数名: log2 *功能: 求以2为底的num的对数 *输入: int型数据num *返回: 以2为底的num的对数 */ intlog2(intnum) { inti,j; i=1; j=2; while(j { j=j*2; i++; } if(j>num) i--; returni; } /* *函数名: GetDataSize *功能: 读入待排序序列长度 */ intGetDataSize() { inti; while(TRUE) { printf("InputtheDataSize: "); scanf("%d",&i); /*读出正确的i,返回;否则,继续要求输入*/ if((i>0)&&(i<=65535)) break; ErrMsg("WrongDataSize,mustbetween[1..65535]"); } returni; } /*输出错误信息*/ ErrMsg(char*msg) { printf("Error: %s\n",msg); } 3.5实验结果 3.6实验总结 通过这次实验,我熟悉快速排序的串行算法和并行算法,并了解了实现快速排序的并行流程图。 但是在实际的操作过程中也遇到了不少问题。 最后是在同学的帮助下完成的。 一、枚举排序算法说明: 枚举排序(EnumerationSort)是一种最为简单的排序算法,通常也被叫做秩排序(RankSort)。 该算法的基本思想是: 对每一个要排序的元素统计小于它的所有元素的个数,从而得到该元素在整个序列中的位置。 其时间复杂度为o(n^2)。 其伪代码为: 输入为: a[1],a[2],...,a[n] 输出为: b[1],b[2],...,b[n] fori=1tondo 1)k=1 2)forj=1tondo ifa>a[j]then k=k+1 endif endfor 3)b[k]=a endfor 算法思想很简单,现将其主要代码总结如下: 1、数组自动生成,随机生成长度为n的数组: 1. 1: voidarray_builder(int*a,intn) 2. 3. 2: { 4. 5. 3: inti; 6. 7. 4: 8. 9. 5: srand((int)time(0)); 10. 11. 6: 12. 13. 7: for(i=0;i 14. 15. 8: a=(int)rand()%100; 16. 17. 9: 18. 19. 10: return; 20. 21. 11: } 复制代码 2、取得每个元素在数组中的秩,即统计每个元素按小于它的其他所有元素的个数: 1. 1: int*get_array_elem_position(int*init_array,intarray_length,intstart,intsize){ 2. 3. 2: 4. 5. 3: inti,j,k; 6. 7. 4: int*position; 8. 9. 5: 10. 11. 6: position=(int*)my_malloc(sizeof(int)*size); 12. 13. 7: for(i=start;i 14. 15. 8: k=0; 16. 17. 9: for(j=0;j 18. 19. 10: if(init_array 20. 21. 11: k++; 22. 23. 12: if((init_array==init_array[j])&&i>j) 24. 25. 13: k++; 26. 27. 14: } 28. 29. 15: 30. 31. 16: position[i-start]=k; 32. 33. 17: } 34. 35. 18: 36. 37. 19: returnposition; 38. 39. 20: } 复制代码 其中my_malloc函数的作用为动态分配大小为size的空间,如分配失败,则终止程序: 1. 1: void*my_malloc(intmalloc_size){ 2. 3. 2: void*buffer; 4. 5. 3: 6. 7. 4: if((buffer=(void*)malloc((size_t)malloc_size))==NULL){ 8. 9. 5: printf("mallocfailure"); 10. 11. 6: exit(EXIT_FAILURE); 12. 13. 7: } 14. 15. 8: 16. 17. 9: returnbuffer; 18. 19. 10: } 复制代码 3、算法主函数: 1. 1: voidserial(){ 2. 3. 2: 4. 5. 3: inti; 6. 7. 4: intarray_length=ARRAY_LENGTH; 8. 9. 5: 10. 11. 6: int*init_array; 12. 13. 7: int*sort_array; 14. 15. 8: int*position; 1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 并行 计算 实验 快速 排序 算法