数据结构 实验四排序.docx
- 文档编号:7409956
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:15
- 大小:205.02KB
数据结构 实验四排序.docx
《数据结构 实验四排序.docx》由会员分享,可在线阅读,更多相关《数据结构 实验四排序.docx(15页珍藏版)》请在冰豆网上搜索。
数据结构实验四排序
2009级数据结构实验报告
实验名称:
实验四——排序
学生姓名:
班级:
班内序号:
学号:
日期:
2009年12月10日
1.实验要求
实验目的:
通过练习下面的题目,学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法使用的情况。
实验内容:
使用简单数组实现下面各种排序算法,并进行比较。
排序算法:
1、插入排序
2、希尔排序
3、冒泡排序
4、快速排序
5、简单选择排序
6、堆排序(选作)
7、归并排序(选作)
要求:
1、测试数据分成三类:
正序、逆序、随机数据
2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数
3、对2和3的结果进行分析,验证上述各种算法的时间复杂度
编写测试main()函数测试线性表的正确性。
2.程序分析
2.1存储结构
顺序存储结构
示意如下:
采用一维数组实现,
排序都是将待排序列按升序排列。
2.2关键算法分析
1)直接顺序排序
算法:
voidInsertSort(intr[],intn)
{
for(inti=2;i { r[0]=r[i];//设置哨兵 for(intj=i-1;r[0] r[j+1]=r[j];//记录后移 r[j+1]=r[0]; } for(intk=1;k cout< cout<<"\n"; } 直接插入排序的基本思想是: 依次将待排序序列中的每一个记录插入到一个已排好序的序列中,直到全部记录都排好序。 如下图: 时间性能: 最好情况: 待排序列为正序,比较n-1次,移动2(n--1)次 最坏情况: 待排序列为逆序,比较(n+2)(n-1)/2次,移动(n+4)(n-1)/2次 平均情况: 要比较有序区中全部记录的一半,比较次数为n(n-1)/4,移动次数为(n+4)(n-1)/4 因此时间复杂度为O(n^2); 空间性能(辅助空间): 只需一个记录的辅助空间(哨兵) 2)希尔排序: 算法: voidShellSort(intr[],intn) { inti; intd; intj; for(d=n/2;d>=1;d=d/2)//以增量为d进行直接插入排序 { for(i=d+1;i { r[0]=r[i];//暂存被插入记录 for(j=i-d;j>0&&r[0] r[j+d]=r[j];//记录后移d个位置 r[j+d]=r[0]; } } for(i=1;i cout< cout<<"\n"; } 希尔排序的基本思想是: 先将整个待排序记录序列分割成若干个子序列,在子序列内分别进行直接插入排序,待整个序列基本有序时,再对全体记录进行一次直接插入排序。 如下图示意: 算法的时间性能: 介于O(n^2)~O(nlog2(n)) 算法的辅助空间: 只需一个辅助记录空间,用于暂存当前待插入的记录。 3)起泡排序 voidBubbleSort(intr[],intn) { inttemp; intexchange; intbound; exchange=n-1;//第一趟起泡排序的范围是r[0]到r[n-1] while(exchange)//仅当上一趟排序有记录交换才进行本趟排序 {++com; bound=exchange; exchange=0; for(intj=0;j if(r[j]>r[j+1]) { com++; temp=r[j]; r[j]=r[j+1]; r[j+1]=temp; exchange=j;//记录每一次发生记录交换的位置 mov+=3; } } for(inti=0;i cout< cout<<"移动次数: "< "< cout<<"\n"; mov=com=0; 起泡排序的基本思想是: 两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。 初始键值序列[5013559727384965] 第一趟排序结果[13505527384965]97 第二趟排序结果[1350273849]556597 第三趟排序结果[13273849]50556597 第四趟排序结果1327384950556597 起泡排序过程示例 时间性能 ·最好情况: 正序,比较n-1次,不交换 ·最坏情况: 反序,比较n(n-1)/2次,移动3n(n-1)/2 时间复杂度为O(n^2) 分析空间性能(辅助空间): 只需一个记录的辅助空间,用来作为记录交换的暂存单元。 4)快速排序 快速排序又称为分区交换排序,其基本思想是: 首先选一个轴值(即比较的基准),将均大于或等于轴值,然后分待排序记录分割成独立的两部分,左侧记录的关键码均小于或等于轴值,右侧记录的关键码别对这两部分重复上述过程,直到整个序列有序。 伪代码: 1.将i和j分别指向待排序区域的最左侧记录和最右侧记录的位置; 2.重复下述过程,直到i=j 2.1右侧扫描,直到记录j的关键码小于基准记录的关键码; 2.2如果i 2.3左侧扫描,直到记录i的关键码大于基准记录的关键码; 2.4如果i 3.退出循环,说明i和j指向了基准记录所在位置,返回该位置; 快速排序一次划分算法: intPartition(intr[],intfirst,intend) { inti=first;//初始化 intj=end; inttemp; while(i {++com; while(i j--;//右侧扫描 com+=2; if(i {++com; temp=r[i];//将较小记录交换到前面 r[i]=r[j]; r[j]=temp; mov+=3; i++; } while(i i++;com+=2;//左侧扫描 if(i { temp=r[j]; r[j]=r[i]; r[i]=temp;//将较大记录交换到后面 j--; mov+=3; } } returni;//i为轴值记录的最终位置 } 示意图如下: 分快速排序算法的时间性能: ·最好情况: O(nlog2(n)) ·最坏情况: 比较n(n-1)/2,移动次数少于比较次数,故时间复杂度为O(n^2); ·平均情况: O(nlog2(n)) 空间性能分析: 需要一个栈来存放每一层递归调用的必要信息,容量与递归深度有关 ·最好情况: O(log2(n)) ·最坏情况: O(n) ·平均情况: O(log2(n)) 5)简单选择排序 简单选择排序是选择排序中最简单的排序方法,其基本思想是: 第i趟排序通过n-i次关键码的比较,在n-i+1(1≤i≤n-1)个记录中选取关键码最小的记录,并和第i个记录交换作为有序序列的第i个记录。 简单选择排序算法: voidSelectSort(intr[],intn) { inti; intj; intindex; inttemp; for(i=0;i {++com; index=i; for(j=i+1;j if(r[j] index=j; ++com; if(index! =i) { com++; temp=r[i]; r[i]=r[index]; r[index]=temp; mov+=3; } } for(i=0;i cout< cout<<"移动次数: "< "< cout<<"\n"; mov=com=0; } 示例如下图: 分简单选择排序算法的时间性能: ·比较次数: 总为n(n-1)/2次 ·移动次数 最好情况: 正序,移动0次 最坏情况: 逆序,移动3(n-1)次 平均情况: O(n^2) 6)堆排序 堆排序的基本思想是: 首先将待排序的记录序列构造成一个堆,此时,选出了堆中所有记录的最大者即堆顶记录,然后将它从堆中移走(通常将堆顶记录和堆中最后一个记录交换),并将剩余的记录再调整成堆,这样又找出了次大的记录,以此类推,直到堆中只有一个记录为止。 堆排序伪代码: 1.设置i和j,分别指向当前要筛选的结点和要筛选结点的左孩子; 2.若结点i已是叶子,则筛选完毕;否则,比较要筛选结点的左右孩子结点(如果有右孩子),并将j指向关键码较大的结点; 3.将要筛选结点i的关键码与j所指向的结点的关键码进行比较 3.1如果结点i的关键码大,则完全二叉树已经是堆,筛选完毕; 3.2否则将r[i]与r[j]交换;令i=j,转步骤2继续进行筛选; 堆排序算法: voidHeapSort(intr[],intn) { inti; inttemp; for(i=n/2;i>=0;i--)//初始建堆,从最后一个非终端结点至根结点 { Sift(r,i,n); com++; } for(i=n-1;i>0;i--)//重复执行移走堆顶及重建堆的操作 {++com; temp=r[i]; r[i]=r[0]; r[0]=temp; Sift(r,0,i-1); mov+=3; } for(i=0;i cout< cout<<"移动次数: "< "< cout<<"\n"; mov=com=0; } 示例如下图: 算法时间性能的分析: 建堆需要O(n)时间,第i次取堆顶记录重建堆需要用O(log2(i))时间,并需要去n-1次堆顶记录,因此总的时间复杂度为O(nlog2(n))。 堆排序对原始记录的排列状态不敏感。 7)归并排序的非递归算法 二路归并排序的过程: 将具有n个待排序的记录序列看成n个长度为1的有序序列,然后进行两两归并,得到[n/2]个长度为2(最后一个有可能为1)的有序序列,让后两两归并,得到[n/4]个长度为4的有序序列(最后一个有可能长度小于4),……,直至得到一个长度为n的有序序列。 一趟归并 voidMergePass(intr[],intr1[],intn,inth) { inti=0; intk; while(i<=n-2*h)//待归并记录至少有两个长度为h的子序列 { com++; Merge(r,r1,i,i+h-1,i+2*h-1); i+=2*h; } if(i {com++; Merge(r,r1,i,i+h-1,n);//待归并序列中有一个长度小于h } elsefor(k=i;k<=n;k++)//待归并序列中只剩一个子序列 {r1[k]=r[k];mov++;com++; } } 算法的时间性能: O(nlog2(n)) 算法的空间性能: O(n) 3.程序运行结果 主函数流程图: 4.总结 排序时数据处理是经常使用的一种操作,合适的排序算法可以大大地减小程序运行的时间复杂度和辅助空间复杂度,因而对排序的研究和掌握是十分必要的,有很重要的理论和实际意义。 通过这次试验队时间复杂度和空间复杂度的计算有了更进一步的认识,认识到算法优化的作用,掌握了各种排序算法的优劣,以及各种算法使用的情况。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 实验四排序 实验 排序