排序算法综合实验.docx

上传人:b****5 文档编号:7330175 上传时间:2023-01-23 格式:DOCX 页数:17 大小:23.03KB
下载 相关 举报
排序算法综合实验.docx_第1页
第1页 / 共17页
排序算法综合实验.docx_第2页
第2页 / 共17页
排序算法综合实验.docx_第3页
第3页 / 共17页
排序算法综合实验.docx_第4页
第4页 / 共17页
排序算法综合实验.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

排序算法综合实验.docx

《排序算法综合实验.docx》由会员分享,可在线阅读,更多相关《排序算法综合实验.docx(17页珍藏版)》请在冰豆网上搜索。

排序算法综合实验.docx

排序算法综合实验

排序算法综合实验

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=1

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="<

"<

}while(choice!

=0);

deleteR;deleteS;

//deleteR1;

}

 

5、实验结果与分析

1、实验结果

实验数据及结果见首页汇总表。

2、实验分析

2.1直接插入排序

该算法虽然简单,但效率不高。

由汇总表的数据可以看出,若初始数据为正序,总的关键字比较次数为最小,并且总的移

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

当前位置:首页 > 初中教育 > 科学

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

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