排序算法综合实验.docx
- 文档编号:7330175
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:17
- 大小:23.03KB
排序算法综合实验.docx
《排序算法综合实验.docx》由会员分享,可在线阅读,更多相关《排序算法综合实验.docx(17页珍藏版)》请在冰豆网上搜索。
排序算法综合实验
排序算法综合实验
1、实验目的
通过上机来体验和掌握课本的有关基本知识,加深对排序算法的认识
2、实验要求
1.实现基本排序方法:
直接插入、希尔、直接选择、冒泡、快速、堆、二路归并;
2.每种基本排序方法尽量给出多种实现(包括改进);
3.给出实验结果:
(1)随机生成若干个随机数进行排序(如n=104,2*104,105,…等),记录每个排序的时间耗费、比较次数、移动次数。
(2)分别给出正序和反序的初始序列进行排序,检验算法对初始序列的敏感程度。
(3)给出实验结果、原因分析、结论等。
(4)所有实验结果汇集成一张表。
3、几种排序算法
1、直接插入排序
1.1原理
在排序过程中,每次都将无序区中第1条记录插入到有序区中适当位置,使其仍保持有序。
初始时,取第1条记录为有序区,其他记录为无序区。
随着排序过程的进行,有序区不断扩大,无序区不断缩小。
最终无序区为空,有序区包含了全部记录,排序结束。
1.2算法
1.2.1带监视哨
voidInsertSort(listR,intn){
inti,j;
for(i=0;i<=n;i++){//依次插入R[2],R[3],...,R[n]
if(CPP,R[i].key>=R[i-1].key)continue;//R[i]大于有序区最后一个记录,不需要插入
MPP,R[0]=R[i];//R[0]是监视哨
j=i-1;
do{//查找R[i]的插入位置
MPP,R[j+1]=R[j];j--;//记录后移,继续向前搜索
}while(CPP,R[0].key
MPP,R[j+1]=R[0];//插入R[i]
}
}
1.2.2无监视哨
voidInsertSort2(listR,intn){//直接插入排序,无监视哨
inti,j;rectypex;//x为辅助量
for(i=2;i<=n;i++){//进行n-1次插入
for(CPP,R[i].key>=R[i-1].key)continue;
MPP,x=R[i];//待排记录暂存到x
j=i-1;
do{//顺序比较和移动
MPP,R[j+1]=R[j];j--;
}while(j>=1&&(CPP,x.key MPP,R[j+1]=x;//插入R[i] } } 1.2.3改进: 在查找插入位置时采用二分查找,即二分插入排序 voidInsertSort3(listR,intn){ inti,j,low,high,mid; for(i=2;i<=n;i++){//依次插入R[2],R[3],...,R[n] if(CPP,R[i].key>=R[i-1].key)continue;//R[i]大于有序区最后一个记录,不需插入 MPP,R[0]=R[i]; low=1;high=i-1; while(low<=high){//查找R[i]的插入位置 mid=(low+high)/2; if(CPP,R[0].key elselow=mid+1; } for(j=i-1;j>=high+1;j--) MPP,R[j+1]=R[j];//记录后移 MPP,R[high+1]=R[0]; } } 2、希尔排序 2.1原理 将数据表分成若干组,所有相隔为某个“增量”的记录为一组,在各组内进行直接插入排序;初始时增量d1较大,分组较多(每组的记录数少),以后增量逐渐减少,分组减少(每组的记录数增多),直到最后增量为1(d1>d2>...>dt=1),所有记录为同一组,再整体进行一次直接插入排序。 2.2算法 voidShellSort(listR,intn){ inth,i,j,k; for(h=n/2;h>=1;h=h/2){ for(i=1;i<=h;i++){//i为组号 for(j=i+h;j<=n;j+=h){//每组从第2个记录开始插入 if(CPP,R[j].key>=R[j-h].key)continue;//R[j]大于有序区最后一个记录,则不需要插入 MPP,R[0]=R[j];//R[0]保存待插入记录,但不是监视哨 k=j-h;//待插记录的前一个记录 do{//查找正确的插入位置 MPP,R[k+h]=R[k];k=k-h;//后移记录,继续向前搜索 }while(k>0&&(CPP,R[0].key MPP,R[k+h]=R[0];//插入R[j] } } if(h==1)break; } } 3、直接选择排序 3.1原理 首先,所有记录组成初始无序区R[1]~R[n],从中选出最小的记录,与无序区第一个记录R[1]交换;新的无序区为R[2]~R[n],从中再选出最小的记录,与无序区第一个记录R[2]交换;类似,滴i趟排序时R[1]~R[i-1]是有序区,无序区为R[i]~R[n],从中选出最小的记录,将它与无序区第一个记录R[i]交换,R[1]~R[i]为新的有序区。 因为没糖排序都使有序区中增加一个记录,所以,进行n-1趟排序后,整个数据表就全部有序了。 3.2算法 voidSelectSort(listR,intn){ inti,j,k; for(i=1;i<=n-1;i++){//n-1趟排序 k=i; for(j=i+1;j<=n;j++)//在当前无序区中找最小的记录R[k] if(R[j].key<=R[k].key)CPP,k=j; if(k! =i){MP3,R[0]=R[i];R[i]=R[k];R[k]=R[0];}//交换R[i]和R[k],R[0]作辅助 } } 4、冒泡排序 4.1原理 设想数据表R[1]~R[n]垂直放置,将每个记录R[i]看作是重量为R[i].key的气泡;根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡违反本原则的轻气泡,就使其向上“漂浮”,如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。 4.2算法 4.2.1上升法 voidBubbleSort1(listR,intn){ inti,j,flag;rectypex;//x为辅助量(可用R[0]代替) for(i=1;i<=n-1;i++){//做n-1趟扫描 flag=0;//置未交换标志 for(j=n;j>=i+1;j--)//从下向上扫描 if(CPP,R[j].key flag=1; MP3,x=R[j];R[j]=R[j-1];R[j-1]=x;//交换 } if(! flag)break;//本趟未交换过记录,排序结束 } } 4.2.2下沉法 voidBubbleSort2(listR,intn){ inti,j,flag;rectypex;//x为辅助量(可用R[0]代替) for(i=1;i<=n-1;i++){//做n-1趟扫描 flag=0;//置未交换标志 for(j=1;j<=n-i;j++)//从上向下扫描 if(CPP,R[j].key>R[j+1].key){//交换记录 flag=1; MP3,x=R[j];R[j]=R[j+1];R[j+1]=x;//交换 } if(! flag)break;//本趟未交换过记录,排序结束 } } 4.3.3改进: 双向冒泡排序,每趟排序同时使轻气泡向上“漂浮”,重气泡向下“漂浮” voidBubbleSort3(listR,intn){//双向冒泡排序 inti,j,k,flag;rectypex; i=1;j=n; while(i flag=0;//置未交换标志 for(k=j;k>=i+1;k--)//从下向上扫描 if(CPP,R[k].key flag=1; MP3,x=R[k];R[k]=R[k-1];R[k-1]=x;//交换 } if(! flag)break;//本趟未交换过记录,排序结束 i++; flag=0; for(k=i;k<=j-1;k++)//从上向下扫描 if(CPP,R[k].key>R[k+1].key){//交换记录 flag=1; MP3,x=R[k];R[k]=R[k+1];R[k+1]=x; } if(! flag)break; j--; } } 5、快速排序 5.1原理 在数据表中任取一个作为“基准”,将其余记录分为两组,第一组找那个个记录均小于或等于基准,第二组中个记录均大于或等于基准,而基准就排在这两组中间(这也是该记录的最终位置),这称为一趟快速排序(或一次划分)。 对所分的两组记录分别重复上述方法,直到每组只有1个记录为止。 5.2算法 5.2.1一趟划分算法 intPartition(listR,intp,intq){//对R[p]到R[q]划分,返回基准位置 inti,j;rectypex;//辅助量(可用R[0]代替) i=p;j=q;MPP,x=R[p];//x存基准(无序区第一个记录) do{ while((CPP,R[j].key>=x.key)&&i if(i while((CPP,R[i].key<=x.key)&&i if(i }while(i MPP,R[i]=x;//基准移到最终位置 returni;//最后i=j } 5.2.2主算法 voidQuickSort1(listR,ints,intt){ inti; if(s>=t)return;//只有一个记录或无记录时无需排序 i=Partition(R,s,t);//对R[s]到R[t]做划分 QuickSort1(R,s,i-1);//递归处理左区间 QuickSort1(R,i+1,t);//递归处理右区间 } 6、堆排序 6.1原理 将待排序的记录序列建成一个堆,并借助于堆的性质进行的排序方法就是堆排序。 它的原理: 将原始的n个记录序列建成一个大根堆,称为初始堆,然后将它的根和最后的元素交换,除此之外的n-1个记录序列再重复上面的操作,直到记录序列为一个递增的序列。 因此,堆排序的操作分为建立初始堆和用堆进行排序两步操作。 6.2算法 6.2.1建立初始堆算法 6.2.1.1非递归算法 voidSift1(listR,intp,intq)//堆范围为R[p]~R[q],调整R[p]为堆 {intj; MPP,R[0]=R[p];//R[0]作辅助量 j=2*p; while(j<=q) { if(j if(CPP,R[0].key>=R[j].key)break;//跟结点键值大于孩子结点,已经是堆,调整结束 MPP,R[p]=R[j];//将R[j]换到双亲位置上 p=j;//修改当前被调整结点 j=2*p;//j指向R[p]的左孩子 } MPP,R[p]=R[0]; } 6.2.1.2递归算法 voidSift2(listR,intp,intq)//堆范围为R[p]~R[q],调整R[p]为堆 { intj; if(p>=q)return;//只有一个元素 j=2*p; if(j>q)return; if(j if(CPP,R[p].key>=R[j].key)return;//根结点关键字已最大 MPP,R[0]=R[j];//交换R[j]和R[p],R[0]作辅助量 MPP,R[j]=R[p];MPP,R[p]=R[0];Sift2(R,j,q); } 6.2.2堆排序算法 voidHeapSort(listR,intn)//堆排序主程序 { inti; for(i=n/2;i>=1;i--)Sift1(R,i,n);//建初始堆 for(i=n;i>=2;i--){//进行n-1趟堆排序 MPP,R[0]=R[1];//堆顶和当前堆底交换,R[0]作辅助量 MPP,R[1]=R[i];MPP,R[i]=R[0];Sift1(R,1,i-1); } 7、二路归并排序 7.1原理 将待排序记录R[0]到R[n-1]看成n个长度为1的有序子序列区,从第一个子序列开始,把相邻的子序列两两归并,便得到[n/2](取整数)个长度为2或1有序的子序列。 然后再把这[n/2]个有序的子序列利用上面的方法两两归并,如此反复,直到最后得到一个长度为n的有序序列。 7.2算法 7.2.1一趟归并算法 voidMerge(listR,listR1,intlow,intmid,inthigh){ //合并R的两个子表: R[low]~R[mid]、R[mid+1]~R[high],结果在R1中 inti,j,k; i=low; j=mid+1; k=low; while(i<=mid&&j<=high) if(CPP,R[i].key<=R[j].key)MPP,R1[k++]=R[i++];//取小者复制 elseMPP,R1[k++]=R[j++]; while(i<=mid)MPP,R1[k++]=R[i++];//复制左子表的剩余记录 while(j<=high)MPP,R1[k++]=R[j++];//复制右子表的剩余记录 } voidMergePass(listR,listR1,intn,intlen){//对R做一趟归并,结果在R1中 inti,j; i=1;//i指向第一对子表的起始点 while(i+2*len-1<=n){//归并长度为len的两个子表 Merge(R,R1,i,i+len-1,i+2*len-1); i=i+2*len;//i指向下一对子表起始点 } if(i+len-1 Merge(R,R1,i,i+len-1,n); else//子表个数为奇数,剩一段 for(j=i;j<=n;j++)//将最后一个子表复制到R1中 MPP,R1[j]=R[j]; } 7.2.2二路归并算法 voidMergeSort(listR,listR1,intn){//对R二路归并排序,结果在R中(非递归) intlen; len=1; while(len MergePass(R,R1,n,len);len=len*2;//奇趟归并,结果在R1中 MergePass(R1,R,n,len);len=len*2;//偶趟归并,结果在R中 } } 4、头文件与主函数等 #include"stdio.h" #include"fstream.h" #include #include #include #include #defineCPPC++ #defineMPPM++ #defineMP2M+=2 #defineMP3M+=3 constintd=3; constintr=10; constintmaxsize=10000000;//数据表容量 typedefintdatatype; typedefstruct { intf,e; }queue; typedefstruct{ datatypekey;//关键字域 datatypekey1[d]; intnext; }rectype;//记录类型 typedefrectypelist[maxsize+2];//数据表类型,0号单元不用 __int64C,M;//比较和移动次数 voidcheck(listR,intn){//检验排序结果 inti; for(i=2;i<=n;i++) if(R[i].key \n";return;} cout<<"Correct! "; } voiddisp(listR,intn){//显示排序后的结果 inti; for(i=1;i<=n;i++){ cout< //if(i%20==0)cout< } cout< } ………… intrandom1(intnum){returnrand();}//0~RAND_MAX=32767 intrandom3(intnum){//素数模乘同余法,0~M intA=16807;//16807,39722040,764261123,63036001648271? intM=2147483647;//有符号4字节最大素数,2^31-1 intQ=M/A; intR=M%A; staticintx=1,n=0,g=0;//seed(setto1) staticdoubler,r1=0,r2=0; intx1; x1=A*(x%Q)-R*(x/Q); if(x1>=0)x=x1; elsex=x1+M; returnx; } intmain(){ rectype*R,*R1,*S;//R1用于归并排序的辅助存储,S用于保存初始排序数据 R=newlist;if(R==NULL){cout<<"数组太大! \n";exit(-1);} R1=newlist;if(R1==NULL){cout<<"数组太大! \n";exit(-1);} S=newlist;if(S==NULL){cout<<"数组太大! \n";exit(-1);} inti,n=maxsize; intchoice; clock_tt1,t2; floats,t; //for(i=1;i<=n;i++)//正序序列 //S[i].key=i; //for(i=1;i<=n;i++)//反序排序 //S[i].key=n-i+1; //srand((unsigned)time(NULL)); for(i=1;i<=n;i++) S[i].key=random3(n);//生成0-n之间的随机数 do{ C=M=0; for(i=1;i<=n;i++) R[i].key=S[i].key;//取出初始数据用于排序 cout<<"选择排序方法(0: 退出): \n\ 11: 直接插入(带监视哨)12: 直接插入(无监视哨)\n\ 13: 二分插入排序\n\ 21: 冒泡(上升)22: 冒泡(下沉)\n\ 23: 双向冒泡排序\n\ 31: 快速(递归)\n\ 41: 二路归并(非递归)\n\ 51: 堆排序(非递归)52: 堆排序(递归)\n\ 61: 选择排序\n\ 71: 希尔排序\n"; cin>>choice; switch(choice){ case11: t1=clock();InsertSort1(R,n);t2=clock(); break; case12: t1=clock();InsertSort2(R,n);t2=clock(); break; case13: t1=clock();InsertSort3(R,n);t2=clock(); break; case21: t1=clock();BubbleSort1(R,n);t2=clock(); break; case22: t1=clock();BubbleSort2(R,n);t2=clock(); break; case23: t1=clock();BubbleSort3(R,n);t2=clock(); break; case31: t1=clock();QuickSort1(R,1,n);t2=clock(); break; case41: t1=clock();MergeSort(R,R1,n);t2=clock(); break; case51: t1=clock();HeapSort1(R,n);t2=clock(); break; case52: t1=clock();HeapSort2(R,n);t2=clock(); break; case61: t1=clock();SelectSort(R,n);t2=clock(); break; case71: t1=clock();ShellSort(R,n);t2=clock(); break; default: ; } check(R,n); //disp(R,n); cout<<"C="< cout<<"时间: "< }while(choice! =0); deleteR;deleteS; //deleteR1; } 5、实验结果与分析 1、实验结果 实验数据及结果见首页汇总表。 2、实验分析 2.1直接插入排序 该算法虽然简单,但效率不高。 由汇总表的数据可以看出,若初始数据为正序,总的关键字比较次数为最小,并且总的移
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 排序 算法 综合 实验