数据库系统实现两阶段多路归并排序算法的C实现.docx

上传人:b****7 文档编号:9635898 上传时间:2023-02-05 格式:DOCX 页数:24 大小:261.69KB
下载 相关 举报
数据库系统实现两阶段多路归并排序算法的C实现.docx_第1页
第1页 / 共24页
数据库系统实现两阶段多路归并排序算法的C实现.docx_第2页
第2页 / 共24页
数据库系统实现两阶段多路归并排序算法的C实现.docx_第3页
第3页 / 共24页
数据库系统实现两阶段多路归并排序算法的C实现.docx_第4页
第4页 / 共24页
数据库系统实现两阶段多路归并排序算法的C实现.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

数据库系统实现两阶段多路归并排序算法的C实现.docx

《数据库系统实现两阶段多路归并排序算法的C实现.docx》由会员分享,可在线阅读,更多相关《数据库系统实现两阶段多路归并排序算法的C实现.docx(24页珍藏版)》请在冰豆网上搜索。

数据库系统实现两阶段多路归并排序算法的C实现.docx

数据库系统实现两阶段多路归并排序算法的C实现

两阶段多路归并排序

Two-PhaseMultiwayMerge-Sort

实验报告

 

目录

1实验目的4

2实验内容4

3实验环境4

4实验的设计和实现4

4.1算法描述4

4.2设计思路5

4.3数据结构6

4.4具体实现7

5实验结果10

5.150MB内存TPMMS实验结果10

5.210MB内存TPMMS实验结果10

5.3100MB内存TPMMS实验结果11

5.4三者的比较12

6实验遇到的问题和解决方法12

6.1Phase2阶段遇到的问题和解决方法12

6.2生成子记录文件名的方法14

7代码附录14

1实验目的

通过merge-sort算法的实现,掌握外存算法所基于的I/O模型与内存算法基于的RAM模型的区别;理解不同的磁盘访问优化方法是如何提高数据访问性能的。

2实验内容

生成一个具有10,000,000个记录的文本文件,其中每个记录由100个字节组成。

实验只考虑记录的一个属性A,假定A为整数类型。

记录在block上封装时,采用non-spanned方式,即块上小于一个记录的空间不使用。

Block的大小可在自己的操作系统上查看,xp一般为4096bytes。

在内存分配50M字节的空间用于外部merge-sort。

要求设计和实现程序完成下列功能:

1)生成文本文件,其中属性A的值随机产生。

2)按照ppt中的方法对文本文件中的记录,按照属性A进行排序,其中在第二阶段的排序中每个子列表使用一个block大小的缓冲区缓冲数据。

3)按照教材cylinder-basedbuffers(1Mbytes)的方法,修改第二阶段的算法。

4)比较两种方法的时间性能,如果有更大的内存空间,算法性能还能提高多少?

3实验环境

1)VisualC++6.0

2)Windows7操作系统

4实验的设计和实现

1

2

3

4

4.1算法描述

Two-PhaseMultiwayMerge-Sort算法的具体描述分为2个阶段,如下所示:

●Phase1

1)Fillmainmemorywithrecords.

2)Sortwithfavoritemainmemorysortingalgorithms.

3)Writesortedlisttodisk.

4)Repeatuntilallrecordshavebeenputintooneofthesortedlists.

●Phase2

1)Initiallyloadinputbufferswiththefirstblockoftheirrespectivesortedlists.

2)Repeatedrunacompetitionamongthefirstunchosenrecordsofeachofthebufferedblocks.

3)Ifaninputblockisexhausted,getthenextblockfromthesamefile.

4)Iftheoutputblockisfull,writeittodisk.

4.2设计思路

从上述的算法描述中,我们知道,系统主要由2大模块组成:

Phase1和Phase2。

Phase1阶段主要将生成的记录文件按内存块大小(本实验中是50MB)分成多个(本实验中是20个)相应的子记录文件,把这些文件中的记录读进内存进行排序,再写回磁盘上。

Phase2阶段利用多路归并排序算法,将Phase1阶段已经排好序的子记录文件重新归并为1个有序的记录文件,写回到磁盘上。

由于我们在Phase1和Phase2阶段之前必须先生成1个含有10000000个100B记录的文件,所以系统必须再加上1个生成记录文件的GenerateRecordFile模块。

终上所述,系统由3大模块组成,分别为:

GenerateRecordFile、Phase1、Phase2。

Phase1模块可以细分为内存块排序模块MainMemorySort和写回磁盘模块WriteToDisk。

Phase2模块可以细分为多路归并排序模块Merge-Sort和写回磁盘模块WriteToDisk。

详细的系统逻辑结构图如图3-1所示:

图3-1TPMMS系统逻辑结构图

4.3数据结构

我们讨论单个记录的数据结构。

由于1个记录有100个字节,其中4字节是由随机整数组成的主键属性PrimaryKey,另外96个字节是随意填充的数据content,而且本系统又是由C语言进行实现的,所以我们可以采取结构体来作为记录的数据结构。

其中整形字段key记录4字节的主键属性,以便进行排序工作。

数组字段contents用来填充剩余的96个字节,内容可以随意(本实验中均为0)。

具体的数据结构如图4-1所示:

图4-1单个记录的数据结构

4.4具体实现

1

2

3

4

4.1

4.2

4.3

4.4

4.4.1GenerateRecordFile阶段

GenerateRecordFile阶段比较简单,首先打开一个文件,然后生成随机数key并将其写入文件中,再填充96个任意内容的字节(本实验中均为0),即能生成1条完整的记录。

重复10000000次,生成我们所需的记录文件。

核心代码实现如图4-2所示,其中MAX_RECORD_NUMBER大小为10000000,ROW_NUMBER大小为95。

图4-2GenerateRecordFile阶段的实现

4.4.2Phase1阶段

Phase1阶段重点在于如何进行内存排序,并写回到磁盘上。

这里我们采用了STL的sort函数帮助我们进行排序。

首先读入50MB记录,利用sort函数进行排序后,写到磁盘上生成1个有序的子记录文件。

重复进行20次,生成20个相应的子记录文件。

核心代码实现如图4-3所示,其中BLOCK_SIZE大小为50M,SUB_LIST_NUMBER大小为20。

图4-3Phase1阶段的实现

4.4.3Phase2阶段

Phase2阶段是本系统实现的难点所在。

主要的实现大致可以分为以下几部分进行讨论:

1)输入缓冲的实现

将Phase1阶段中得到的20个子记录文件的首字符分别读入长度为20的输入缓冲数组inputBuffer,核心代码实现如图4-4所示:

图4-4输入缓冲的实现

2)输出缓冲的实现

选取输入缓冲数组inputBuffer中主键属性key最小的那个缓冲区,输入到输出缓冲数组outputBuffer中,然后循环执行,核心代码实现如图4-5所示:

图4-5输出缓冲的实现

3)多路归并排序的实现

如果输出缓冲数组outputBuffer已经填满,此时可知输出缓冲是有序的,且之后的主键属性key的值都不会小于该输出缓冲区,这时我们即可将其输出到最后想要得到的结果文件上,核心代码实现如图4-6所示:

图4-6多路归并排序的实现

4)Phase2阶段的其他实现

我们将在“实验中遇到的问题和解决办法”这一章详细讨论Phase2阶段剩下来的难点实现。

5实验结果

1

2

3

4

5

5.150MB内存TPMMS实验结果

采用50MB内存块大小进行TPMMS实验的结果如图5-1所示:

图5-150MB内存TPMMS实验结果图

从上图可以看出,生成1GB大小10000000条记录的文件需要152秒,phase1阶段需要136秒,phase2阶段需要150秒。

所以整个排序过程需要286秒,即4分46秒的时间才能完成。

5.210MB内存TPMMS实验结果

我们将50MB内存缩减5倍,进行10MB内存块大小的TPMMS实验。

这将产生100个子记录文件。

实验结果如图5-2所示:

图5-210MB内存TPMMS实验结果图

生成1GB大小10000000条记录的文件所需时间不变,仍为152秒左右。

我们注重于phase1阶段和phase2阶段的所需时间。

从图中可以看出,phase1阶段需要147秒,phase2阶段需要152秒。

整个排序过程需要300秒,即5分钟的时间才能完成。

5.3100MB内存TPMMS实验结果

我们再将50MB内存增加2倍,进行100MB内存块大小的TPMMS实验。

这将产生10个子记录文件。

实验结果如图5-3所示:

图5-3100MB内存TPMMS实验结果图

生成1GB大小10000000条记录的文件所需时间不变,仍为152秒左右。

我们注重于phase1阶段和phase2阶段的所需时间。

从图中可以看出,phase1阶段需要124秒,phase2阶段需要130秒。

整个排序过程需要254秒,即4分14秒的时间才能完成。

5.4三者的比较

从上面的实验结果,我们可以很明显地看出,内存块大小越大,算法所需时间越少。

这是因为内存块越小,生成的子记录文件个数就越多,这样phase1阶段生成子记录文件的时间就增加了。

并且这还使得phase2阶段的输出缓冲区变小,导致多路归并时程序读写磁盘的次数增多,所以phase2阶段时间也增加了。

这样整个排序过程时间当然增加。

终上所述,当在理想条件下,我们应使用内存块大小较大的方法来进行TPMMS算法的实现。

在本章中TPMMS算法的性能为:

100MB优于50MB优于10MB。

所以在可能的情况下,应该考虑采纳100MB的TPMMS算法。

6实验遇到的问题和解决方法

1

2

3

4

5

6

6.1Phase2阶段遇到的问题和解决方法

前文已经详细描述了Phase2阶段的3个主要的实现阶段,但是仅仅依靠这3个阶段还不能完全实现Phase2阶段,必须解决以下几个关键问题才能完成Phase2阶段的所有任务。

6.1.1读完某个子记录文件后,输入缓冲的填充方法

当某个输入缓冲数组inputBuffer[i]相对应的子记录文件infp[i]已经读完时,我们就必须重新查找其余可用的子记录文件,按数组下标i搜索到第一个可用的文件infp[k]后,将它的第一个字节继续填充到输入缓冲数组inputBuffer[i]中。

特别的,当数组下标i超过子记录文件总数SUB_LIST_NUMBER(本实验中为20)时,我们就认为所有子记录文件已经读取完毕,这时可以设置一个bool型变量flag=true,进行标识。

核心代码实现如图6-1所示:

图6-1读完某个子记录文件后,输入缓冲的填充方法

6.1.2读完所有子记录文件后,处理最后一组输入缓冲数据的方法

利用在6.1.1中设置的bool型变量flag,当flag=true时,我们知道子记录文件已经全部读取完毕。

这时在输入缓冲数组inputBuffer中只剩下最后一组数据,并且根据Phase2阶段的定义,它们肯定比之前输入缓冲中的数据要大。

所以我们只需利用STL提供的sort函数对它们进行排序后,直接输出到最终结果文件即可。

核心代码实现如图6-2所示:

图6-1读完所有子记录文件后,处理最后一组输入缓冲数据的方法

6.2生成子记录文件名的方法

当我们生成子记录文件时,想要赋予文件类似于record_k.txt(k=i+1,0<=i<=19)的文件名。

由于在C语言中,不支持字符串和整数的直接连接。

在这里我们需要一个generateFileName函数,采用itoa函数将整数k=i+1转换成字符串,再连接到“record_”后面,从而得到想要的文件名。

核心代码实现如图6-3所示:

图6-3生成子记录文件名的方法

7代码附录

#include//forsortfunction

#include//forstrcpy

#include//forfscanf,fprintf,fopen

#include//forclock

usingnamespacestd;

/*definetheconstantsusedinthisprogram*/

constintMAX_RECORD_NUMBER=10000000;//maxrecordnumber

constintBLOCK_SIZE=500000;//mainmemoryblocksize

constintROW_NUMBER=95;//forrecordtofilltheother96bytes

constintSUB_LIST_NUMBER=(MAX_RECORD_NUMBER/BLOCK_SIZE);//sublistnumber

constintMAX=99999999;//forfunctionselectMinRecordtoinitializethevariable"min"

/*thedatastructrueofarecord*/

typedefstructrecord

{

intkey;//primarykey

charcontents[ROW_NUMBER+1];//content

}Record;

RecordsubRecord[BLOCK_SIZE];//mainmemorybuffer

RecordinputBuffer[BLOCK_SIZE+1];//inputbuffer

RecordoutputBuffer[BLOCK_SIZE+1];//outputbuffer

/*generateafileofMAX_RECORD_NUMBER(=10000000)records,

everyrecordis100bytes*/

voidgenerateFile(stringfileName)

{

//calculatetime

printf("Therecordsisnowundergenerating...\n");

clock_tstart,finish;

doubleduration;

start=clock();//starttime

//openfile

FILE*fp=fopen(fileName.c_str(),"w");

if(!

fp)//openfailed

{

printf("Filecouldnotbecreated!

\n");

fprintf(stderr,"Filecouldnotbecreated!

\n");

exit

(1);

}

//generaterandomintegersandrecords

srand((unsigned)time(NULL));//srandseed

for(inti=0;i

{

if(i>0)

fprintf(fp,"\n");

intkey=rand();//primarykey,randominteger,4bytes

//writerecordtodisk,everyrecordhas100bytes

fprintf(fp,"%d",key);//writekeyasthefirst4bytes

for(intj=0;j

fprintf(fp,"%c",'0');

}

fclose(fp);//closeoutputfile

//calculatetime

finish=clock();//finishtime

duration=(double)(finish-start)/CLOCKS_PER_SEC;//runtime

printf("Ittakes%fsecondstogenetatethewholerecords.\n",duration);

}

/*useforphase1oftwophasemultiwaymergesort

comparetworecordbyprimarykey,withascendingorder*/

boolcmp(constRecord&r1,constRecord&r2)

{

returnr1.key

}

/*giveaninteger,togenerateafilename*/

stringgenerateFileName(inti)

{

charstr[20];//temporarycharaterarray

stringtemp="";//temporarystring

itoa(i+1,str,10);//storeintegerk+1toarraystr

temp=str;//convertarraystrtotemporarystring

temp="D:

/record_"+temp+".txt";//formthefilename

returntemp;//returnthetemporarystringoffilename

}

/*phase1oftwophasemultiwaymergesort

readrecordwithmaximumblocksizetomainmemory

andsortthembyprimarykey*/

voidphase1(stringfileName)

{

//openfile

FILE*infp=fopen(fileName.c_str(),"r");

if(!

infp)//openfailed

{

printf("File%scouldnotbeopened!

\n",fileName.c_str());

fprintf(stderr,"File%scouldnotbeopened!

\n",fileName.c_str());

exit

(1);

}

stringtemp="";//temporarystring

inti=0,j=0;

//calculatetime

printf("Thesortedlistofrecordsisnowundergenerating...\n");

clock_tstart,finish;

doubleduration;

start=clock();//starttime

charstr[ROW_NUMBER+10];

//readallrecordstomainmemory

for(intk=0;k

{

//readrecordsofablocksizetomainmemory

for(i=0;i

{

fgets(str,ROW_NUMBER+10,infp);

sscanf(str,"%d%s",&subRecord[i].key,subRecord[i].contents);

}

//useSTLalgorithmsorttosortrecords

sort(subRecord,subRecord+BLOCK_SIZE,cmp);

temp=generateFileName(k);//sortedlistname

FILE*outfp=fopen(temp.c_str(),"w");//openoutputfile

if(!

outfp)//openfailed

{

printf("File%scouldnotbeopened!

\n",temp.c_str());

fprintf(stderr,"File%scouldnotbeopened!

\n",temp.c_str());

exit

(1);

}

//writethesortedrecordstosublistfile

for(i=0;i

{

if(i>0)

fprintf(outfp,"\n");

fprintf(outfp,"%d%s",subRecord[i].key,subRecord[i].contents);

}

printf("Thesortedlist%sgeneratedsuccessfully!

\n",temp.c_str());

fclose(outfp);//closeoutputstream

}

fclose(infp);//closeinputfile

//calculatetime

finish=clock();//finishtime

duration=(double)(finish-start)/CLOCKS_PER_SEC;//runtime

printf("Ittakes%fsecondstogenetatethesortedlistofrecords.\n",duration);

}

/*copyrecordr2torecordr1*/

voidcopyRecord(Record&r1,Record&r2)

{

r1.key=r2.key;

strcpy(r1.contents,r2.contents);

}

/*copyarecordtoinputbuffer*/

voidcopyToInputBuf

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

当前位置:首页 > 党团工作 > 入党转正申请

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

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