数据结构课程设计实验报告内部排序算法比较.docx

上传人:b****7 文档编号:11193648 上传时间:2023-02-25 格式:DOCX 页数:36 大小:1.36MB
下载 相关 举报
数据结构课程设计实验报告内部排序算法比较.docx_第1页
第1页 / 共36页
数据结构课程设计实验报告内部排序算法比较.docx_第2页
第2页 / 共36页
数据结构课程设计实验报告内部排序算法比较.docx_第3页
第3页 / 共36页
数据结构课程设计实验报告内部排序算法比较.docx_第4页
第4页 / 共36页
数据结构课程设计实验报告内部排序算法比较.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

数据结构课程设计实验报告内部排序算法比较.docx

《数据结构课程设计实验报告内部排序算法比较.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计实验报告内部排序算法比较.docx(36页珍藏版)》请在冰豆网上搜索。

数据结构课程设计实验报告内部排序算法比较.docx

数据结构课程设计实验报告内部排序算法比较

内部排序算法比较

【实验简介】

1、在教科书各种内部排序算法的时间复杂度分析结果只给出了算法执行的时间的阶,或大概的执行时间,如:

直接插入排序即时间复杂度为O(n*n)

2、通过五组随机数据、一组正序数据与一组逆序数据比较6种常用的内部算法(起泡排序、直接插入排序、简单选择排序、快速查找排序、希尔排序、堆排序)的关键字比较次数和关键字移动次数,以取得直观感受;

3、用五组不同的长度不小于100的数据进行测试,并对测试结果作出简单的分析,对得出结果拨动大小的进行解释;

【设计模块】

【对应模块算法说明】

(1)此算法程序中需要用到顺序表数据类型,数据元素的类型定义如下:

typedefstruct{

KeyTypekey;//关键字项

}RedType;

typedefstruct{

RedTyper[MAXSIZE+1];//0号单元闲置或用作哨兵单元

intlength;//顺序表长度

intinfo;//记录关键字移动次数

intcmp;//关键字的比较次数

}Sqlist;

(2)本实验用到六种排序算法,一个主函数和菜单函数,其中排序算法分别为起泡排序、直接插入排序、简单选择排序、快速查找排序、希尔排序、堆排序;相应时间复杂度分析如下:

起泡排序:

若待排序列为“正序”,则需进行一趟排序在排序过程中关键字需进行n-1次比较,无须移动纪录;若是“逆序”,则进行n-1趟排序,需n(n-1)/2次比较,并坐等数量级的移动,因此总的事件复杂度为O(n2);

直接插入排序待排序纪录是随机的,关键字间的移动次数和比较次数的平均值约为n*n/4,即时间复杂度为O(n2);

简单的选择排序虽然在排序过程中所需要的移动次数较少,最小时为0,最大时为3(n-1);但是关键字的比较次数总是相同的,均为n(n-1)/2,因此,时间复杂度亦为O(n2);

快速排序其平均时间是kn*㏑n,其中n为待排序列中纪录的个数,k为某个常数,其时间复杂度为O(n*㏑n);

希尔排序当增序序列为dlta[k]=2t-k+1-1时,时间复杂度为O(n3/2),其中t为排序趟数,1≤k≤t≤㏒2(n+1);

堆排序此排序对于含n个元素的序列排序时,总共进行的关键字比较次数不超过4n,且在最坏的情况下,其时间复杂度为O(n*㏑n);

算法分析如下:

①冒泡排序该算法的的思路是首先将第1个记录的关键字负值给L.r[0],然后用L.r[0]与第(i+1)个记录的关键字比较,若为逆序,则交换第i与第i+1两记录的位置,然后让i加1,重复以上操作,直至i=n-1为止;依次进行第二趟、第三趟……作同样的操作,直至所有的记录按正序排列(一般需要n-1趟比较,第i趟从L.r[1]到L.r[n-i+1]依次比较,1≦i≦n-i,比较结果是让其中最大的记录放在L.r[n-i+1]的位置)

voidBubbleSort(Sqlist*L)//冒泡排序

{

for(i=0;ilength;i++)

{

L->r[0]=L->r[1];

for(j=1;j

if(L->r[0].key>=L->r[j+1].key)

L->r[j]L->r[j+1];//交换两记录的位置

else

L->r[0]=L->r[j+1];//保证L->r[0]始终为较大的记录

L->r[j+1]=L->r[0];//把最大的记录放到祠堂排序的最高位置

}

printf(L->r[MAXSIZE]);//输出排序后数组和相关数据

}

②直接插入排序本算法的思路是,把L->r[0]设置为哨兵,排序时把第i个记录复制给哨兵,并于其前的i-1个记录进行比较,找到第一个比起大的记录,利用循环让记录后移,把其放到第一个比起大的记录前面。

voidinsertSort(Sqlist*L)//直接插入排序

{

for(i=2;i<=L->length;i++)

{

if((L->r[i].keyr[i-1].key))

{

L->r[0]=L->r[i];//复制哨兵

L->r[i]=L->r[i-1];

for(j=i-2;(L->r[0].keyr[j].key);j--)

L->r[j+1]=L->r[j];//纪录后移

L->r[j+1]=L->r[0];//插入到正确位置

}

}

printf(L->r[MAXSIZE]);//输出排序后数组和相关数据

}

③简单选择排序基本思想是在第i趟选择排序时:

通过n-i次关键字之间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1≦i≦n)个记录交换之

voidSelectSort(Sqlist*L)//简单选择排序

{

for(i=1;i<=L->length;++i)//选择第i小的记录,并交换到位

{

L->r[0]=L->r[i];j=i;

for(k=i+1;k<=L->length;k++)//从L.r[i..L.length]中选key最小的

if(L->r[0].key>L->r[k].key)

{

L->r[0]=L->r[k];

j=k;

}

if(i!

=j)

L.r[i]←→L.r[j];//与第i个记录交换

}

printf(L->r[MAXSIZE]);//输出排序后数组和相关数据

}

④快速查找排序其基本思想为,通过一趟排序将带排序记录分割成两部分,其中一部分记录的关键字均小于另一部分的关键字,再利用递归分别对分割所得到的子序列进行快速排序。

其中一趟快速排序的算法为:

intserchSort(Sqlist*L,intlow,inthigh)//快速排序单次排序

{

pivotkey=L->r[low].key;//枢轴纪录关键字

while(low

{

while(lowr[high].key>=pivotkey)high--;

L->r[low]L->r[high];//将比枢轴纪录小的纪录移到底端

while(lowr[low].key<=pivotkey)low++;

L->r[high]L->r[low];//将比枢轴纪录大的纪录移到高端

}

returnhigh;//返回枢轴所在位置

}

递归算法为:

voidQSort(Sqlist*L,intlow,inthigh)//快速排序

{

if(low

{//长度大于1

pivotloc=serchSort(L,low,high);//调用serchSort()将L.r[low..high]一分为二

QSort(L,low,pivotloc-1);//对低子表递归排序,pivotloc是枢轴位置

QSort(L,pivotloc+1,high);//对高子表递归排序

}

}

⑤希尔排序基本思路是先将整个待排序的记录分割成若干个子序列进行直接排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次全体直接插入排序

voidShellSort(Sqlist*L,intdlta[],intt)//希尔排序

{

for(k=1;k<=t;k++)

{

dlta[k]=(int)pow(2,t-k+1)-1;//doublepow(doublebase,doubleexp);函数返回以参数base为底的exp次幂

for(i=dlta[k]+1;i<=L->length;i++)

if(L->r[i].keyr[i-dlta[k]].key)

{

L->r[0]=L->r[i];

for(j=i-dlta[k];j>0&&(L->r[0].keyr[j].key);j-=dlta[k])

L->r[j+dlta[k]]=L->r[j];

L->r[j+dlta[k]]=L->r[0];

}

}

printf(L->r[MAXSIZE]);//输出排序后数组和相关数据

}

⑥堆排序基本思想是使记录序列按关键字非递减有序排列,则再对排序的算法中先建立一个“大顶堆”,即先选得一个关键字为最大的记录与序列中最后一个记录交换,然后再对序列中前n-1记录进行筛选,重新将它调整为“大顶堆“,如此反复直至排序结束。

voidHeapAdjust(Sqlist*L,ints,intm){//已知L.r[s..m]中记录的关键字除L.r[s].key之外均满足堆的定义,本函数调整L.r[s]的关键字,使L.r[s..m]成为一个大顶堆(对其中记录的关键字而言)

rc=L->r[s];

for(j=2*s;j<=m;j*=2){//沿key较大的孩子结点向下筛选

if(jr[j].keyr[j+1].key)++j;//j为key较大记录的下标

if(rc.key>=L->r[j].key)break;//rc应插入在位置s上

L->r[s]=L->r[j];

s=j;

}

L->r[s]=rc;//插入

}

voidHeapSort(Sqlist*L)//堆排序

{

for(i=L->length/2;i>0;i--)//把H->r[…]建成大顶堆

HeapAdjust(L,i,L->length);

for(i=L->length;i>1;i--)

L->r[i]L->r[1];//将堆顶记录和当前未经排序子序列L.r[1…i]中

//最后一个记录相互交换

HeapAdjust(L,1,i-1);//将H.r[1..i-1]重新调整为大顶堆

}

printf(L->r[MAXSIZE]);//输出排序后数组和相关数据

}

⑦菜单程序利用dowhile循环实现对菜单的正确选择,并返回选择的操作代码

intmenu_select()//菜单目录

{

intnu;

chars;

printf("************************************************\n");

printf("*****菜单*****\n");

printf("1.BubbleSort\n");//冒泡排序

printf("2.insertSort\n");//直接插入排序

printf("3.SelectSort\n");//简单选择排序

printf("4.QSort\n");//查找排序

printf("5.ShellSort\n");//希尔排序

printf("6.HeapSort\n");//堆排序

printf("7.退出程序\n");

printf("************************************************\n");

printf("请输入数字:

1-7选择相应的排序方式或操作:

\n");

do

{

s=getchar();

nu=(int)s-48;

}while(nu<0||nu>55);

return(nu);

}

⑧主函数是程序的入口,包括两个for循环,一个用来实现随机数产生与输出;另一个用来实现菜单的选择的连续;第二个for循环中包含一个switch循环,作用是根据菜单程序的返回值选择相应的操作,随后作相应的修改使待排序数据分别为正序和逆序,以实现本设计的目的。

voidmain()

{

printf("输出待排序的数据:

");

for(;;)

switch(menu_select())//选择相应的排序操作

{

case1:

BubbleSort(&A);break;

case2:

insertSort(&B);break;

case3:

SelectSort(&C);break;

case4:

QSort(&L,1,L.length);break;

case5:

ShellSort(&D,dlta,t);break;

case6:

HeapSort(&E);break;

case7:

exit(0);

}

}

运行结果:

第一组随机数据及其运行结果如下:

第二组随机数据及其运行结果如下:

第三组随机数据及其运行结果如下:

第四组随机数据及其运行结果如下:

第五组随机数据及其运行结果如下:

第六组正序数据及其运行结果如下:

第七组逆序数据及其运行结果如下:

【小结与讨论】

表中数据为关键字移动次数:

BubbleSort

insertSort

SelectSort

QSort

ShellSort

HeapSort

第一组

6974

2690

605

393

723

1082

第二组

7066

2473

586

382

742

1081

第三组

7072

2733

592

408

724

1075

第四组

7068

2587

583

368

788

1087

第五组

6963

2787

620

402

754

1085

第六组

9900

0

0

297

0

1136

第七组

4950

5148

2650

297

540

1012

下表中数据为关键字比较次数:

BubbleSort

insertSort

SelectSort

QSort

ShellSort

HeapSort

第一组

4950

2504

4950

638

785

749

第二组

4950

2293

4950

635

790

752

第三组

4950

2550

4950

600

796

752

第四组

4950

2404

4950

625

824

748

第五组

4950

2607

4950

621

804

745

第六组

4950

99

4950

4950

480

811

第七组

4950

4950

4950

4950

672

662

有数据分析可知:

无论待排序列排序如何,BubbleSort与SelectSort两种算法的关键字比较次数均为4950,即n(n-1)/2次;待排序列为随机序列时直接插入排序的关键字比较次数和关键字移动平均值约为n2/4,正序时比较次数为(n-1),移动次数为0,逆序时为n(n-1)/2次;整体看来六种排序中QSort、ShellSort、HeapSort三种排序比较和移动次数相对较少;但BubbleSort、insertSort两种排序属于稳定性排序(每交换一次纪录,关键字就有三次移动纪录)。

在测试过程中,当连续选择一个操作时,发现有的排序方式的关键字移动次数会随之增加,例如BubbleSort,QSort,HeapSort;仔细分析后得知,无论待排序列是否排好,它每次运行都会有关键字的移动;每次运行程序,六种排序方式的关键字比较次数也会随着操作次数的增加而增加,原因与上一个问题先同。

 

【程序清单】

#include

#include

#include

#include

#include

#defineMAXSIZE100

typedefintKeyType;//定义关键字的整数类型

typedefstruct{

KeyTypekey;//关键字项

}RedType;

typedefstruct{

RedTyper[MAXSIZE+1];//0号单元闲置或用作哨兵单元

intlength;//顺序表长度

intinfo;//记录关键字移动次数

intcmp;//关键字的比较次数

}Sqlist;

/**********************************************************************/

voidBubbleSort(Sqlist*L)//冒泡排序

{

inti,j;

intN=L->length;

for(i=0;ilength;i++)

{

L->r[0]=L->r[1];

for(j=1;j

{

if(L->r[0].key>=L->r[j+1].key)

{

L->r[j]=L->r[j+1];

L->info++;

}

else

{

L->r[j]=L->r[0];

L->r[0]=L->r[j+1];

L->info+=2;

}

L->cmp++;

L->r[j+1]=L->r[0];

}

}

printf("以下数据的排列顺序为BubbleSort排序后的排列顺序:

\n");

for(i=1;i<=MAXSIZE;i++)

printf("%d\t",L->r[i]);//输出排序后数组和相关数据

printf("关键字移动次数为:

%d\n",L->info);

printf("关键字比较次数为:

%d\n",L->cmp);

}

/**********************************************************************/

voidinsertSort(Sqlist*L)//直接插入排序

{

inti,j;

for(i=2;i<=L->length;i++)

{

L->cmp++;

if((L->r[i].keyr[i-1].key))

{

L->r[0]=L->r[i];//复制哨兵

L->r[i]=L->r[i-1];

L->info+=2;

for(j=i-2;(L->r[0].keyr[j].key);j--)

{

L->r[j+1]=L->r[j];//纪录后移

L->info++;

L->cmp++;

}

L->r[j+1]=L->r[0];//插入到正确位置

L->info++;

}

}

printf("以下数据的排列顺序为insertSort排序后的排列顺序:

\n");

for(i=1;i<=L->length;i++)

printf("%d\t",L->r[i]);//输出排序后数组和相关数据

printf("关键字移动次数为:

%d\n",L->info);

printf("关键字比较次数为:

%d\n",L->cmp);

}

/**********************************************************************/

voidSelectSort(Sqlist*L)//简单选择排序

{

inti,j,k;

for(i=1;i<=L->length;++i)//选择第i小的记录,并交换到位

{

L->r[0]=L->r[i];j=i;

for(k=i+1;k<=L->length;k++)//在L.r[i..L.length]中选key最小者

{

L->cmp++;

if(L->r[0].key>L->r[k].key)

{

L->r[0]=L->r[k];

j=k;

L->info++;

}

}

if(i!

=j)

{//L.r[i]←→L.r[j];与第i个记录交换

RedTypetemp;

temp=L->r[i];

L->r[i]=L->r[j];

L->r[j]=temp;

L->info+=3;

}

}

printf("以下数据的排列顺序为SelectSort排序后的排列顺序:

\n");

for(i=1;i<=L->length;i++)

printf("%d\t",L->r[i]);//输出排序后数组和相关数据

printf("关键字移动次数为:

%d\n",L->info);

printf("关键字比较次数为:

%d\n",L->cmp);

}

/**********************************************************************/

intserchSort(Sqlist*L,intlow,inthigh)//查找排序单次排序

{

intpivotkey;

L->r[0]=L->r[low];

pivotkey=L->r[low].key;//枢轴纪录关键字

while(low

{

while(lowr[high].key>=pivotkey)

{

high--;

L->cmp++;

}

L->r[low]=L->r[high];//将比枢轴纪录小的纪录移到底端

L->info++;

while(lowr[low].key<=pivotkey)

{

low++;

L->cmp++;

}

L->r[high]=L->r[low];//将比枢轴纪录大的纪录移到高端

L->info++;

}

L->r[low]=L->r[0];

L->info++;

returnhigh;

}

voidQSort(Sqlist*L,intlow,inthigh)//快速排序

{

intpivotloc;

if(low

{//长度大于1

pivotloc=serchSort(L,low,high);//将L.r[low..high]一分为二

QSort(L

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

当前位置:首页 > 农林牧渔 > 农学

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

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