并行归并排序.docx
- 文档编号:12273705
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:21
- 大小:147.50KB
并行归并排序.docx
《并行归并排序.docx》由会员分享,可在线阅读,更多相关《并行归并排序.docx(21页珍藏版)》请在冰豆网上搜索。
并行归并排序
串行归并与并行归并排序算法
串行归并排序算法
归并排序是一种很容易进行并行化的算法,因为归并的各个数据区间都是独立的,没有依赖关系。
并且归并排序是一种速度比较快的排序,且是一种稳定的排序算法,排序速度与关键词初始排列无关。
串行归并排序的算法大体的可以描述为:
首先将要排序的表分成两个节点个数基本相等的子表,然后对每个子表进行排序,最后将排好序的两个子表合并成一个子表。
在对子表进行排序时可以将子表再分解成两个节点数量基本相同的子表,当子表足够小时,也可以采用其他排序方法对子表进行排序,然后再对排好
序的子表进行归并操作,最后将整个表排好序。
1、1算法流程图
并行归并排序算法的流程图:
串行归并排序算发流程图
1、2代码分析
#include
usingnamespacestd;
#defineN11
intarray[N]={4,67,456,23,1,78,26,222,34,432,12};待//排序数组intother[N];//辅助空间,用以暂存已经排序的数组元素
voidSwap(int&a,int&b)
{
inttmp=a;
a=b;
b=tmp;
}
/*array待排序数组
*begin数组开始的下标
*end数组最后一个元素的下标
*/
voidMergeSort(int*array,intbegin,intend){
if(end-begin+1>2)
{
MergeSort(array,begin,(end+begin)/2);MergeSort(array,(end+begin)/2+1,end);
inti=begin,j=(end+begin)/2+1,k=begin;while(i<=(begin+end)/2&&j<=end){if(array[i] else other[k++]=array[j++]; } while(i<=(begin+end)/2) other[k++]=array[i++]; while(j<=end)other[k++]=array[j++];for(k=begin;k<=end;++k)array[k]=other[k]; }else if(array[end] voidOutput(int*array,intn) { for(inti=0;i cout< cout«endl; } intmain() { cout«"串行归并排序算法"< "; Output(array,N); MergeSort(array,0,N-1); cout<<"thesortedresult: "; Output(array,N); inti; cin>>i; return0; } 1、3运行结果 Ic: sandSeftiDLKsVAdBinistratorVBjrDomentsWisnuaJL thenumbersare•46? 45623178262223443212thesortedresultil4122326346? 782234324S6 1、4复杂度分析 通过算法分析很容易发现串行归并排序算法的时间复杂度地推公式为: '° (1) '丿if(n=1) T(n)=n [2T(3)+o(n)if(n>1) 这是一个时间复杂度的递推公式,我们需要消去等号右侧的T(n),把T(n) 写成n的函数。 其实符合一定条件的Recurrenee的展开有数学公式可以套,这里我们略去严格的数学证明,只是从直观上看一下这个递推公式的结果。 当n=1时可以设T (1)=g,当n>1时可以设T(n)=2丁("厂3,我们取C1和C2中较大 2 的一个设为c,把原来的公式改为: T(n)=」 c if(n=1) n、.,八 2匕)cnif(nJ 参照主定理公式T(n)=aTf(n),可以知道当n>1时,有以下 b 等式成立: a2 b=2 f(n)二cn 同时又有下面的等式成立: f(n)=cn=&(nlogb) 则有T(n)满足主定理公式的第二种情况,也即是T(n)的时间复杂度为: T(n)=°(nlo“lgn)=°(nlgn) 并行归并排序算法 由串行归并排序算法可知,归并的各个数据区间都是独立的,没有依赖关系。 因此归并排序是一种很容易进行并行化的算法。 其方案是先将待排序区间划分成若干个相等的小区间,然后并行地对这些小区间进行排序,最后再通过归并的方法将所有排好序的小区间归并成一个有序系列。 由于归并时是一层层向上进行的,因此需要将区间划分成2k个小区间,这样第1轮归并时,可以将2k个小区间归并成2kJ个区间。 这样过k轮归并操作后就归并成一个有序的大区间。 这也正是并行归并排序的算法思想。 2、1算法流程图 并行归并排序算法的思想可以通过下面的流程图表示: 开始 并行归并排序算发流程图 2、2代码分析 功能函数头文件: MergeSort.h #defineMAX_MERGE_TURN24 #defineMIN_PARALLEL_SORT_COUNT3 #defineMIN_MERGE_COUNT2 #defineCACHE_LINE_SIZE64typedefunsignedintUINT; #include #include #include #include #include intcompare(int*one,int*two){ if(*one>*two) return1; elseif(*two>*one) return-1; elsereturn0; } void*GetCacheAlignedAddr(void*pAddr) { intm=CACHE_LINE_SIZE; void*pRet=(void*)(((UINT)pAddr+m-1)&(-m)); returnpRet;} /**串行归并函数 归并好的数据存放在输出参数ppNewDat中 @paramvoid**ppData-待归并的数据 @paramintnStart1- @paramintnEnd1- 第个区间的开始位置(包括nStart1) 第个区间的结束位置(包括nEnd1) @paramintnStart2-第个区间的开始位置(包括nStart2) @paramintnEnd2-第个区间的结束位置(包括nEnd2) @paramCOMPAREFUNCfunc比-较函数 @paramvoid**ppNewData-存放归并后的数据 @returnvoid**-返回归并后的数据指针(等于ppNewData) */ int**Serial_Merge(int**ppData,intnStart1,intnEnd1,intnStart2,intnEnd2,int(*func)(int*,int*),int**ppNewData) { inti,j,k; i=nStart1;j=nStart2;k=nStart1; for(i=nStart1;i<=nEnd1;) { for(;j<=nEnd2;j++) { if((*func)(ppData[i],ppData[j])<0) { ppNewData[k]=ppData[i]; ++k; i++; break; } else { ppNewData[k]=ppData[j];++k; } } //如果j已经到了尾部 if(j>nEnd2) { for(;i<=nEnd1;i++) { ppNewData[k]=ppData[i];++k; break; if(i>nEnd1) { for(;j<=nEnd2;j++) { ppNewData[k]=ppData[j];++k; } } for(i=nStart1;i<=nEnd2;i++){ ppData[i]=ppNewData[i]; } returnppData; } /**串行归并排序函数 @paramvoid**ppData-待排序数据@paramintnBegin-排序区间的开始位置 @paramintnEnd-排序区间的结束位置 @paramCOMPAREFUNCfunc数-据大小比较函数 @returnvoid-无 */ voidSerial_MergeSort(int**ppData,intnBegin,intnEnd,int(*func)(int*,int*)) { if(nEnd-nBegin int*temp; if(*ppData[nBegin]>*ppData[nEnd]) { temp=ppData[nBegin];ppData[nBegin]=ppData[nEnd];ppData[nEnd]=temp; } return; } int**tempData=newint*[nEnd-nBegin+1];inti; inttmpInt=0; for(i=0;i { tempData[i]=&tmpInt; } intnMid=(nBegin+nEnd)>>1;//除以 Serial_MergeSort(ppData,nBegin,nMid,func); Serial_MergeSort(ppData,nMid+1,nEnd,func); Serial_Merge(ppData,nBegin,nMid,nMid+1,nEnd,func,tempData);} /**并行归并快速排序函数 @paramvoid**ppData-待排序数据 @paramintnLen-待排序数据长度 @paramCOMPAREFUNCfunc数-据比较回调函数@returnvoid-无 */ voidParallel_MergeSort(int**ppData,intnLen,int(*func)(int*,int*)) { inti,k; intnStep; intnLoopCount; intnCore;intnStart1,nEnd1; if(nLen { Serial_MergeSort(ppData,0,nLen-1,func);return; } nCore=omp_get_num_procs(); intnCount=nLen/MIN_PARALLEL_SORT_COUNT; intnTurn=MAX_MERGE_TURN; nLoopCount=1< while(nLoopCount>nCount) { nLoopCount=nLoopCount>>1;//除以 --nTurn; } //判断nTurn是否为奇数 if((nLoopCount>nCore)&&(nTurn>0x1)&& ((nTurn&0x1)==0x1)) { --nTurn;//把nTurn变成偶数,便于后面不拷贝数据nLoopCount=nLoopCount>>1; } nStep=nLen/nLoopCount; int*p=newint[nLoopCount*2+CACHE_LINE_SIZE];int*pnPos=(int*)GetCacheAlignedAddr(p); //将数据分成nLoopCount个小区间,并行地对每个区间进行串行排序 #pragmaompparallelforprivate(nStart1,nEnd1)num_threads(nCore) for(i=0;i { nStart1=i*nStep; nEnd1=nStart1+nStep-1; if(i==nLoopCount-1) {nEnd1=nLen-1; } Serial_MergeSort(ppData,nStart1,nEnd1,func);pnPos[i+i]=nStart1; pnPos[i+i+1]=nEnd1; } //对排好序的各个相邻区间进行并行归并操作 int**pp=newint*[nLen+CACHE_LINE_SIZE]; int**ppOutData=(int**)GetCacheAlignedAddr((int*)pp); int**ppMergeData=ppData; int**ppTempOutData=ppOutData; int**ppSwap; nStep=2; for(k=0;k { #pragmaompparallelfornum_threads(nCore) for(i=0;i { intnPos=i*nStep; Serial_Merge(ppMergeData,pnPos[nPos],pnPos[nPos+1],pnPos[nPos+nStep],pnPos[nPos+nStep+1],func,ppTempOutData); pnPos[nPos+1]=pnPos[nPos+nStep+1]; } nLoopCount=nLoopCount>>1;//除以 nStep+=nStep; ppSwap=ppMergeData; ppMergeData=ppTempOutData; ppTempOutData=ppSwap; } //将数据写回到ppData中,如果nTurn为偶数则下面的判断内的循环不会被 执行 if(ppMergeData==ppOutData) { #pragmaompparallelfornum_threads(nCore)for(i=0;i { ppData[i]=ppOutData[i]; } } delete[]p;delete[]pp; return; 测试文件: Test.cpp #include"MergeSort.h"//testMergeSort voidtestFunc(intsize) { Sleep(IOOO);//防止srand取同样的值 inti;intcost; SYSTEMTIMElpsystimeStr; SYSTEMTIMElpsystimeEnd; newint*[size]; newint*[size];newint[size]; newint[size]; int**ppDataForSerial=int**ppDataForParallel=int*tempArrForSerial=int*tempArrForParallel= srand((unsignedint)time(O)); for(i=O;i { tempArrForSerial[i]=rand();tempArrForParallel[i]=tempArrForSerial[i];ppDataForSerial[i]=tempArrForSerial+i;ppDataForParallel[i]=tempArrForParallel+i; } cout<<"测试"< "< GetLocalTime(&lpsystimeStr); printf("开始时间: %年%月%日星 期%u%u: %u: %u: %u\n: lpsystimeStr.wYear,lpsystimeStr.wMonth,lpsystimeStr.wDay,lpsystimeStr.wDayOfWeek,lpsystimeStr.wHour,lpsystimeStr.wMinute,lpsystimeStr.wSecond,lpsystimeStr.wMilliseconds); Serial_MergeSort(ppDataForSerial,0,size-1,compare); GetLocalTime(&lpsystimeEnd); printf("结束时间: %1年%i月%日星 期%u%u: %u: %u: %u\n: lpsystimeEnd.wYear,lpsystimeEnd.wMonth,lpsystimeEnd.wDay,lpsystimeEnd.wDayOfWeek,lpsystimeEnd.wHour,lpsystimeEnd.wMinute,lpsystimeEnd.wSecond,lpsystimeEnd.wMilliseconds); cost=lpsystimeEnd.wMilliseconds-lpsystimeStr.wMilliseconds; if(cost<=0) { cost=cost+(lpsystimeEnd.wSecond-lpsystimeStr.wSecond)* 1000; } cout<<"共耗时: "< "< cout<<"串行归并排序后前个数字: "; for(i=0;i<10;i++) { if(0==i%6) cout< cout<<*ppDataForSerial[i]<<""; } cout< cout< cout<<"测试"< "< GetLocalTime(&lpsystimeStr); printf("开始时间: %U年%i月%日星 期%u%u: %u: %u: %u\n: lpsystimeStr.wYear,lpsystimeStr.wMonth,lpsystimeStr.wDay,lpsystimeStr.wDayOfWeek,lpsystimeStr.wHour,lpsystimeStr.wMinute,lpsystimeStr.wSecond,lpsystimeStr.wMilliseconds); Parallel_MergeSort(ppDataForParallel,size,compare); GetLocalTime(&lpsystimeEnd); printf("结束时间: %1年%月%日星 期%u%u: %u: %u: %u\n: lpsystimeEnd.wYear,lpsystimeEnd.wMonth,lpsystimeEnd.wDay,lpsystimeEnd.wDayOfWeek,lpsystimeEnd.wHour,lpsystimeEnd.wMinute,lpsystimeEnd.wSecond,lpsystimeEnd.wMilliseconds); cost=lpsystimeEnd.wMilliseconds-lpsystimeStr.wMilliseconds; if(cost<=0) { cost=cost+(lpsystimeEnd.wSecond-lpsystimeStr.wSecond)* 1000; } "< IIII cout<<"共耗时: "< cout<<"并行归并排序后前个数字: "for(i=0;i<10;i++) { if(0==i%6) cout< cout<<*ppDataForParallel[i]<< } cout< cout< delete[]tempArrForSerial;delete[]tempArrForParallel; delete[]ppDataForSerial;delete[]ppDataForParallel; } intmain() { testFunc(500);testFunc(10000);testFunc(50000);testFunc(100000);testFunc(500000);testFunc(800000);testFunc(1000000);return0; } 2、3运行结果 90耶109911VS&G1995127G473158^ 3? 1411H715351155631787124889 25730261763005636583 洌试10fl呼个数窃任归并算 2012^3g! 7B 片间: 泗12年3月即日 (7V耗日7hlt0nso 舁轩归并排序石前⑷个数字 测试50©个数宇幷jf归并尊注旺始时㉑汕曄年m月汐日J结朿日寸间,2“2年3月貂日J共耗时・^Gna□ 坪忏归井排序石前加个数字: 7710
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 并行 归并 排序