数据库系统实现两阶段多路归并排序算法的C实现Word文档下载推荐.docx
- 文档编号:22771915
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:24
- 大小:261.69KB
数据库系统实现两阶段多路归并排序算法的C实现Word文档下载推荐.docx
《数据库系统实现两阶段多路归并排序算法的C实现Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《数据库系统实现两阶段多路归并排序算法的C实现Word文档下载推荐.docx(24页珍藏版)》请在冰豆网上搜索。
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具体实现
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实验结果
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实验结果图
从图中可以看出,phase1阶段需要124秒,phase2阶段需要130秒。
整个排序过程需要254秒,即4分14秒的时间才能完成。
5.4三者的比较
从上面的实验结果,我们可以很明显地看出,内存块大小越大,算法所需时间越少。
这是因为内存块越小,生成的子记录文件个数就越多,这样phase1阶段生成子记录文件的时间就增加了。
并且这还使得phase2阶段的输出缓冲区变小,导致多路归并时程序读写磁盘的次数增多,所以phase2阶段时间也增加了。
这样整个排序过程时间当然增加。
终上所述,当在理想条件下,我们应使用内存块大小较大的方法来进行TPMMS算法的实现。
在本章中TPMMS算法的性能为:
100MB优于50MB优于10MB。
所以在可能的情况下,应该考虑采纳100MB的TPMMS算法。
6实验遇到的问题和解决方法
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<
algorithm>
//forsortfunction
string>
//forstrcpy
cstdio>
//forfscanf,fprintf,fopen
ctime>
//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,"
exit
(1);
}
//generaterandomintegersandrecords
srand((unsigned)time(NULL));
//srandseed
for(inti=0;
i<
MAX_RECORD_NUMBER;
i++)//generateMAX_RECORD_NUMBERrecords
{
if(i>
0)
fprintf(fp,"
intkey=rand();
//primarykey,randominteger,4bytes
//writerecordtodisk,everyrecordhas100bytes
fprintf(fp,"
%d"
key);
//writekeyasthefirst4bytes
for(intj=0;
j<
ROW_NUMBER;
j++)//write'
0'
forcontentastheother96bytes
%c"
'
fclose(fp);
//closeoutputfile
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<
r2.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)
FILE*infp=fopen(fileName.c_str(),"
r"
infp)//openfailed
printf("
File%scouldnotbeopened!
fileName.c_str());
inti=0,j=0;
printf("
Thesortedlistofrecordsisnowundergenerating...\n"
charstr[ROW_NUMBER+10];
//readallrecordstomainmemory
for(intk=0;
k<
SUB_LIST_NUMBER;
k++)
//readrecordsofablocksizetomainmemory
for(i=0;
BLOCK_SIZE;
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(),"
//openoutputfile
if(!
outfp)//openfailed
printf("
temp.c_str());
fprintf(stderr,"
temp.c_str());
exit
(1);
//writethesortedrecordstosublistfile
i++)
if(i>
fprintf(outfp,"
fprintf(outfp,"
subRecord[i].key,subRecord[i].contents);
Thesortedlist%sgeneratedsuccessfully!
fclose(outfp);
//closeoutputstream
fclose(infp);
//closeinputfile
Ittakes%fsecondstogenetatethesortedlistofrecords.\n"
/*copyrecordr2torecordr1*/
voidcopyRecord(Record&
r1,Record&
r1.key=r2.key;
strcpy(r1.contents,r2.contents);
/*copyarecordtoinputbuffer*/
voidcopyToInputBuf
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据库 系统 实现 阶段 归并 排序 算法