并行归并排序.docx

上传人:b****5 文档编号:12273705 上传时间:2023-04-17 格式:DOCX 页数:21 大小:147.50KB
下载 相关 举报
并行归并排序.docx_第1页
第1页 / 共21页
并行归并排序.docx_第2页
第2页 / 共21页
并行归并排序.docx_第3页
第3页 / 共21页
并行归并排序.docx_第4页
第4页 / 共21页
并行归并排序.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

并行归并排序.docx

《并行归并排序.docx》由会员分享,可在线阅读,更多相关《并行归并排序.docx(21页珍藏版)》请在冰豆网上搜索。

并行归并排序.docx

并行归并排序

串行归并与并行归并排序算法

串行归并排序算法

归并排序是一种很容易进行并行化的算法,因为归并的各个数据区间都是独立的,没有依赖关系。

并且归并排序是一种速度比较快的排序,且是一种稳定的排序算法,排序速度与关键词初始排列无关。

串行归并排序的算法大体的可以描述为:

首先将要排序的表分成两个节点个数基本相等的子表,然后对每个子表进行排序,最后将排好序的两个子表合并成一个子表。

在对子表进行排序时可以将子表再分解成两个节点数量基本相同的子表,当子表足够小时,也可以采用其他排序方法对子表进行排序,然后再对排好

序的子表进行归并操作,最后将整个表排好序。

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

#includeusingnamespacestd;

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 自我管理与提升

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1