排序实验报告.docx
《排序实验报告.docx》由会员分享,可在线阅读,更多相关《排序实验报告.docx(27页珍藏版)》请在冰豆网上搜索。
排序实验报告
《数据结构》
课程设计报告
专业计算机科学与技术
班级
姓名
学号
指导教师
起止时间2012.12~2013.1
课程设计:
排序综合
一、任务描述
排序综合
任务:
利用随机函数产生n个随机整数(20000以上),对这些数进行多种方法进行排序。
要求:
(1)至少采用三种方法实现上述问题求解(提示,可采用的方法有插入排序、希尔排序、起泡排序、快速排序、选择排序、堆排序、归并排序)。
并把排序后的结果保存在不同的文件中。
(2)统计每一种排序方法的性能(以上机运行程序所花费的时间为准进行对比),找出其中两种较快的方法。
二、问题分析
1、功能分析
分析设计课题的要求,要求编程实现以下功能:
(1)排序表的建立—即创建顺序表;
(2)顺序表的排序—即直接插入排序、希尔排序、起泡排序、快速排序、简单选择排序操作;
(3)统计每一种排序方法的性能—即测试上机运行程序所花费的时间;
2、数据对象分析
数据信息:
随机整数
数据数量可以预先确定(20000以上)
三、数据结构设计
使用顺序表实现,有关定义如下:
typedefintStatus;
typedefintKeyType;//设排序码为整型量
typedefintInfoType;
typedefstruct{//定义被排序记录结构类型
KeyTypekey;//排序码
InfoTypeotherinfo;//其它数据项
}RedType;
typedefstruct{
RedType*r;//存储带排序记录的顺序表
//r[0]作哨兵或缓冲区
intlength;//顺序表的长度
}SqList;//定义顺序表类型
四、功能设计
(一)主控菜单设计
为实现通各种排序的功能,首先设计一个含有多个菜单项的主控菜单程序,然后再为这些菜单项配上相应的功能。
程序运行后,给出6个菜单项的内容和输入提示,如下:
1.直接插入排序
2.希尔排序
3.起泡排序
4.快速排序
5.简单选择排序
0.退出系统
(二)程序模块结构
由课题要求可将程序划分为以下几个模块(即实现程序功能所需的函数):
●主控菜单项选择函数menu()
●创建排序表函数InitList_Sq()
●对顺序表L进行直接插入排序函数Insertsort()
●希尔排序函数ShellSort();
●起泡排序函数Bubble_sort()
●快速排序函数QSort()
●简单选择排序函数SelectSort()
(三)函数调用关系
程序的主要结构(函数调用关系)如下图所示。
Menu()InitList_Sq(L)
Main()
Insertsort(L)ShellSort()Bubble_sort()QSort()SelectSort()
其中main()是主函数,它进行菜单驱动,根据选择项0~5调用相应的函数。
main()函数使用for循环实现重复选择。
其循环结构如下:
for(;;)
{
longstart,end;
switch(menu())
{
case1:
printf("*直接插入排序*\n");
start=clock();
Insertsort(L);
end=clock();
printf("%dms\n",end-start);
fp=fopen("D:
直接插入排序.txt","w");
if(fp==NULL)//打开文件失败
{
printf("打开文件失败!
\n");
exit
(1);
}
for(i=1;i<=L.length;i++)
fprintf(fp,"%d",L.r[i]);
fclose(fp);
break;
case2:
printf("*希尔排序*\n");
start=clock();
ShellSort(L,an,14);
end=clock();
printf("%dms\n",end-start);
fp=fopen("D:
希尔排序.txt","w");
if(fp==NULL)//打开文件失败
{
printf("打开文件失败!
\n");
exit
(1);
}
for(i=1;i<=L.length;i++)
fprintf(fp,"%d",L.r[i]);
fclose(fp);
break;
case3:
printf("*起泡排序*\n");
start=clock();
Bubble_sort(L);
end=clock();
printf("%dms\n",end-start);
fp=fopen("D:
起泡排序.txt","w");
if(fp==NULL)//打开文件失败
{
printf("打开文件失败!
\n");
exit
(1);
}
for(i=1;i<=L.length;i++)
fprintf(fp,"%d",L.r[i]);
fclose(fp);
break;
case4:
printf("*快速排序*\n");
start=clock();
QSort(L,0,L.length);
end=clock();
printf("%dms\n",end-start);
fp=fopen("D:
快速排序.txt","w");
if(fp==NULL)//打开文件失败
{
printf("打开文件失败!
\n");
exit
(1);
}
for(i=1;i<=L.length;i++)
fprintf(fp,"%d",L.r[i]);
fclose(fp);
break;
case5:
printf("*简单选择排序*\n");
start=clock();
SelectSort(L);
end=clock();
printf("%dms\n",end-start);
fp=fopen("D:
简单选择排序.txt","w");
if(fp==NULL)//打开文件失败
{
printf("打开文件失败!
\n");
exit
(1);
}
for(i=1;i<=L.length;i++)
fprintf(fp,"%d",L.r[i]);
fclose(fp);
break;
case0:
printf("\t退出!
\n");
return;
}
}
(四)文件结构
1、sort.h:
顺序表相关的定义与函数声明
2、sort.cpp:
顺序表排序运算的实现
3、menu.h:
主菜单函数的声明
4、menu.cpp:
主菜单函数的实现
5、mn.cpp:
主函数
(五)各函数的算法设计
1、InitList_Sq()
算法原理:
数组指针r指示线性表的基址,length指示线性表的当前长度,将随机生成的数赋给线性表,并生成相应文件。
流程图:
开始
申请内存
随机生成30000个数字
生成文件
Fp=NULL
将顺序表打印到文件内终止程序
关闭文件
结束
代码描述:
StatusInitList_Sq(SqList&L)
{//构造一个线性表
FILE*fp;
L.r=(RedType*)malloc(LIST_INIT_SIZE*sizeof(RedType));
if(!
L.r)exit(OVERFLOW);//存储分配失败
L.length=30001;//表长度为30001
srand((unsigned)time(NULL));
for(inti=1;i<=L.length;i++)
L.r[i].key=rand()%30001+1;
fp=fopen("D:
构造一个线性表.txt","w");
if(fp==NULL)//打开文件失败
{
printf("打开文件失败!
\n");
exit
(1);
}
for(i=1;i<=L.length;i++)
fprintf(fp,"%d",L.r[i]);
fclose(fp);
returnOK;
}//InitList_Sq
算法的时间复杂度分析:
O(n)
2、Insertsort()
算法原理:
每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
在已形成的有序表中顺序查找,并在适当位置插入,把原来位置上的元素向后顺移。
流程图:
开始
i=2
i是
L.r[i].key是
L.r[0]=L.r[i]
j=i-1
L.r[0].key是
L.[j+1]=L.r[j]
j--
L.r[j+1]=L.r[0]
i++
结束
代码描述:
voidInsertsort(SqList&L)//对顺序表L进行直接插入排序
{for(inti=2;i<=L.length;i++)
if(LT(L.r[i].key,L.r[i-1].key))//需将L.r[i]插入有序表
{L.r[0]=L.r[i];//复制为“哨兵”,暂存
for(intj=i-1;LT(L.r[0].key,L.r[j].key);j--)
L.r[j+1]=L.r[j];
//位置j指示了第一个key≤L.r[i].key的元素
L.r[j+1]=L.r[0];//将暂存在r[0]中的记录插入到正确位置
}}
算法的时间复杂度分析:
O(n2)
3、ShellInsert()
算法原理:
1、分组、组内直接插入排序;2、组数逐次减小;3、组数=1,结束。
流程图:
开始
i=dk+1
i是
L.r[i].key是
L.r[0]=L.r[i]
j=i-dk
(j>0)&&(LT(L.r[0].key,L.r[j].key)否
是
L.r[j+dk]=L.r[j]
j-=dk
L.r[j+dk]=L.r[0]
i++
结束
代码描述:
voidShellInsert(SqList&L,intdk)
{//一趟Shell排序,dk为步长
inti;
for(i=dk+1;i<=L.length;i++)
{
if(LT(L.r[i].key,L.r[i-dk].key))
{
L.r[0]=L.r[i];
intj;
for(j=i-dk;(j>0)&&(LT(L.r[0].key,L.r[j].key));j-=dk)
L.r[j+dk]=L.r[j];
L.r[j+dk]=L.r[0];
}
}
}
4、
ShellSort()
流程图:
开始
k=0
kShellInsert(L,dlta[k])
k++
结束
代码描述:
voidShellSort(SqList&L,intdlta[],intt)
{//Shell排序,dlta[]为增量序列,t为增量个数
intk;
for(k=0;kShellInsert(L,dlta[k]);
}//ShellSort
算法的时间复杂度分析:
O(n(㏒2n)2)
5、Bubble_sort()
算法原理:
每趟不断将记录两两比较,若发现逆序,则交换两个记录,使排序码较小的元素逐渐从后部移向前部(就象水底的气泡一样逐渐向上冒)。
流程图:
开始
n=L.length
i=1
iflag=0
j=n-1
j<=i
L.r[j+1].keyflag=1
L.r[j]←→L.r[j+1]
j--
flag=0
i++
结束
代码描述:
voidBubble_sort(SqList&L)
{
RedTypex;
intn;
n=L.length;//表长
for(inti=1;i{intflag=0;//进入循环,清标志
for(intj=n-1;j>=i;j--)
if(LT(L.r[j+1].key,L.r[j].key))
{
flag=1;//有交换,置标志
x=L.r[j];//L.r[j]←→L.r[j+1]
L.r[j]=L.r[j+1];
L.r[j+1]=x;
}
if(flag==0)break;//若无交换则可结束冒泡排序
}
}
算法的时间复杂度分析:
O(n2)
6、Partition()
算法原理:
从n个待排记录中任取一个记录Ri作标准,调整序列中各个记录的位置,使得:
排在ri前的记录排序码<=ri.key排在ri后的排序码,该过程为一趟快速排序。
这样就确定了Ri在序列中的最终位置,同时将序列分成两个子序列。
流程图:
开始
L.r[0]=L.r[low]
Pivotkey=L.r[low].key
Low是
low=pivotkey否
是
--high
L.r[low]←→L.r[high]
low是
++low
L.r[low]←→L.r[high]
L.r[low]=L.r[0]
returnlow
结束
代码描述:
intPartition(SqList&L,intlow,inthigh){
/*交换子表r[low…high]的记录,使枢轴记录到位,并返回其位置。
返回时,在枢轴之前的记录排序码均不大于其排序码,之后的记录排序码均不小于其排序码。
*/
L.r[0]=L.r[low];//以子表的首记录作为枢轴,放入r[0]单
intpivotkey;
pivotkey=L.r[low].key;//取枢轴的排序码存入pivotkey变量
while(lowRedTypex;
RedTypet;
while(low=pivotkey)--high;
x=L.r[low];
L.r[low]=L.r[high];
L.r[high]=x;//将比枢轴排序码小的记录交换到低端
while(lowt=L.r[high];
L.r[high]=L.r[low];
L.r[low]=t;//将比枢轴排序码大的记录交换到高端
}
L.r[low]=L.r[0];//枢轴记录到位
returnlow;//返回枢轴记录所在位置
}//Partition
7、QSort()
算法原理:
1、对Partition()确定的两个子序列分别进行快速排序,则又可确定2个记录在序列中的最后位置,同时将序列分成4个子序列。
2、重复直至每个序列的长度均为1时,全部记录排序完毕。
流程图:
开始
Lowpivotloc=Partition(L,low,high)
QSort(L,low,pivotloc-1)
QSort(L,pivotloc+1,high)
结束
代码描述:
voidQSort(SqList&L,intlow,inthigh){//对顺序表L中的子序列r[low…high]作快速排序
if(low1
intpivotloc;
pivotloc=Partition(L,low,high);//一趟快排,将r[]一分为二
QSort(L,low,pivotloc-1);//在左子区间进行递归快排,直到长度为1
QSort(L,pivotloc+1,high);//在右子区间进行递归快排,直到长度为1
}
}
算法的时间复杂度分析:
O(nlogn)
8、SelectSort()
算法原理:
第1趟:
从R[1]~R[n]中选取最小值,与R[1]交换;
第2趟:
从R[2]~R[n]中选取最小值,与R[2]交换;
………………………
第i趟:
从R[i]~R[n]中选取最小值,与R[i]交换;
………………………
第n-1趟:
从R[n-1]~R[n]中选取最小值,与R[n-1]交换.
共通过n-1趟,得到一个按排序码从小到大排列的有序序列
流程图:
开始
i=1
i是
k=i
j=i+1
j<=L.length否
是
L.r[j].keyk=j
k!
=i否
是
L.r[i]←→L.r[j]
++j
++i
结束
代码描述:
voidSelectSort(SqList&L)
{//对顺序表进行简单选择排序
RedTypex;
for(inti=1;i{//在L.r[i..L.length]中选择key最小的记录
intk=i;
for(intj=i+1;j<=L.length;j++)
if(LT(L.r[j].key,L.r[k].key))k=j;
if(k!
=i){
x=L.r[i];
L.r[i]=L.r[j];
L.r[j]=x;
}
}
}//SelectSort
算法的时间复杂度分析:
算法的改进方法(这部分可以选择):
五、测试数据和结果
1、测试数据
随机产生30000个数
2、测试结果
本程序在VC++环境下实现,下面是对以上测试数据的运行结果。
(1)主菜单显示如下:
(2)建立通信录单链表:
六、结束语
本设计完成了课题要求的任务,较熟练地运用了顺序表来解决问题,实现了顺序表的各种排序的基本算法,设计了较便捷的操作界面。