并行归并排序.docx

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

并行归并排序.docx

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

并行归并排序.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]

other[k++]=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<

}

intmain()

{

cout<<"串行归并排序算法"<

";

Output(array,N);

MergeSort(array,0,N-1);

cout<<"thesortedresult:

";

Output(array,N);

inti;

cin>>i;

return0;

}

1、3运行结果

1、4复杂度分析

通过算法分析很容易发现串行归并排序算法的时间复杂度地推公式为:

这是一个时间复杂度的递推公式,我们需要消去等号右侧的T(n),把T(n)写成n的函数。

其实符合一定条件的Recurrence的展开有数学公式可以套,这里我们略去严格的数学证明,只是从直观上看一下这个递推公式的结果。

当n=1时可以设

,当n>1时可以设

,我们取c1和c2中较大的一个设为c,把原来的公式改为:

参照主定理公式

,可以知道当n>1时,有以下等式成立:

同时又有下面的等式成立:

则有T(n)满足主定理公式的第二种情况,也即是T(n)的时间复杂度为:

二、并行归并排序算法

由串行归并排序算法可知,归并的各个数据区间都是独立的,没有依赖关系。

因此归并排序是一种很容易进行并行化的算法。

其方案是先将待排序区间划分成若干个相等的小区间,然后并行地对这些小区间进行排序,最后再通过归并的方法将所有排好序的小区间归并成一个有序系列。

由于归并时是一层层向上进行的,因此需要将区间划分成

个小区间,这样第1轮归并时,可以将

个小区间归并成

个区间。

这样过k轮归并操作后就归并成一个有序的大区间。

这也正是并行归并排序的算法思想。

2、1算法流程图

并行归并排序算法的思想可以通过下面的流程图表示:

2、2代码分析

功能函数头文件:

MergeSort.h

#defineMAX_MERGE_TURN24

#defineMIN_PARALLEL_SORT_COUNT3

#defineMIN_MERGE_COUNT2

#defineCACHE_LINE_SIZE64

typedefunsignedintUINT;

#include

#include

#include

#include

#include

usingnamespacestd;

intcompare(int*one,int*two)

{

if(*one>*two)

return1;

elseif(*two>*one)

return-1;

else

return0;

}

void*GetCacheAlignedAddr(void*pAddr)

{

intm=CACHE_LINE_SIZE;

void*pRet=(void*)(((UINT)pAddr+m-1)&(-m));

returnpRet;

}

/**串行归并函数

归并好的数据存放在输出参数ppNewData中

@paramvoid**ppData-待归并的数据

@paramintnStart1-第个区间的开始位置(包括nStart1)

@paramintnEnd1-第个区间的结束位置(包括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(1000);//防止srand取同样的值

inti;

intcost;

SYSTEMTIMElpsystimeStr;

SYSTEMTIMElpsystimeEnd;

int**ppDataForSerial=newint*[size];

int**ppDataForParallel=newint*[size];

int*tempArrForSerial=newint[size];

int*tempArrForParallel=newint[size];

srand((unsignedint)time(0));

for(i=0;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:

%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("结束时间:

%u年%u月%u日星期%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年%u月%u日星期%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("结束时间:

%u年%u月%u日星期%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<<*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运行结果

2、4与串行归并排序的性能比较

由于并行归并排序算法采用了多线程在多个CPU上运行,其运行的时间复杂度在理论上应该是比串行归并算法的时间小很多,此处不做具体的分析。

不过需要指出的是,如果数据量非常小的话,串行和并行的归并排序算法在时间上的差异十分不明显。

并且,由于并行归并排

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

当前位置:首页 > 小学教育 > 语文

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

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