实验六各种排序方法的比较
一、实验目的
1.通过实验掌握排序的基本概念,对排序的稳定性及排序的时间复杂性有深刻的认识。
2.掌握各种排序方法的基本思想和算法实现。
3.能够灵活地选用某种排序方法解决问题。
二、实验要求
1.认真阅读和掌握本实验的参考程序。
2.保存程序的运行结果,并结合程序进行分析。
三、实验内容
编写一个程序,对所给的数据(程序中给出或通过键盘初始化均可)进行排序,要求尽可能多的选择不同的排序算法,并显示排序前和排序后的结果。
源程序:
#include
#define MAXSIZE 100
typedef int KeyType;/* 假定关键字类型为整数类型 */
typedef struct {
KeyType key;/* 关键字项 */
}DataType;/* 数据元素类型 */
typedef struct {
DataType r[MAXSIZE +1];/* r[0]闲置或充当前哨站*/
int length;/* 顺序表长度 */
}SqList;/* 顺序表类型 */
//直接插入排序
void StraightInsertSort(SqList *S)
{
int i,j;
for(i=2;i<=S->length;i++)
{ S->r[0]=S->r[i]; /*复制为哨兵*/
j= i-1;
while (S->r[0].key < S->r[j].key)
{
S->r[j+1]=S->r[j];
j-- ;
} /*记录后移*/
S->r[j+1]=S->r[0]; /*插入到正确位置*/
}
for(i=1;i<=S->length;i++)
printf("%d ",S->r[i].key);
printf("稳定");
}
//折半插入排序
void BinaryInsertSort(SqList *s)
{
int low,high,mid;int i,j;
for(i=2;i<=s->length;i++)
{
s->r[0]=s->r[i];//保存带插入元素
low=1;high=i-1;//设置初始区间
while(low { mid=(low+high)/2; if(s->r[0].key>=s->r[mid].key)//保证稳定性排序算法 else high=mid-1; } for(j=i-1;j>=low+1;j--)//low=high s->r[j+1]=s->r[j]; s->r[low+1]=s->r[0]; for(i=1;i<=s->length;i++) printf("%d ",s->r[i].key); printf("稳定"); } } //希尔排序 void ShellInsert(SqList *S,int gap) { /*一趟增量为gap的插入排序,gap为步长*/ int i,j; for(i=gap+1;i<=S->length;i++) if(S->r[i].key { /*小于时,需将r[i]插入有序表*/ S->r[0]=S->r[i]; /*为统一算法设置监视哨*/ for(j=i-gap;j>0 && S->r[0].key S->r[j+gap]=S->r[j]; /*记录后移*/ S->r[j+gap]=S->r[0]; /*插入到正确位置*/ } /* if */ } void ShellSort(SqList *S,int gaps[],int t) { /*按增量序列gaps[0,1…,t-1]对顺序表S作希尔排序*/ int k;int i; for(k=0;k ShellInsert(S,gaps[k]); for(i=1;i<=S->length;i++) printf("%d ",S->r[i].key); printf("不稳定"); /*一趟增量为gaps[k]的插入排序*/ } //冒泡排序 void BubbleSort(SqList *S) { /* 对顺序表S作冒泡排序 */ int i,j; for (i=1;i<=S->length-1;i++) /*进行n-1趟排序*/ { for (j= 2;j<=1+S->length-i; j++) { if (S->r[j].key < S->r[j-1].key) { S->r[0]=S->r[j]; /* S->r[j]与S->r[j-1]交换 */ S->r[j]=S->r[j-1]; S->r[j-1]=S->r[0]; } } } for(i=1;i<=S->length;i++) printf("%d ",S->r[i].key); printf("稳定"); } int QuickSort1 (SqList *S, int low, int high) { KeyType pivotkey; S->r[0]=S->r[low]; /*以子表的第一个记录作为轴值记录*/ pivotkey=S->r[low].key; /*取轴值记录关键字*/ while(low { while(low high--; S->r[low]=S->r[high]; /*将比轴值记录小的交换到低端*/ while (low low++; S->r[high]=S->r[low]; /*将比轴值记录大的交换到高端*/ } S->r[low]=S->r[0]; /*轴值(支点)记录到位*/ return low; /*返回轴值(支点)记录所在位置*/ } SqList* QuickSort(SqList *S,int low,int high) { /*对顺序表S中的子序列r[low…high]作快速排序*/ int pivotloc; if(low { pivotloc= QuickSort1 (S,low,high); /*将待排序序列一分为二*/ QuickSort(S,low,pivotloc-1); /*对小于轴值序列实现递归排序*/ QuickSort(S,pivotloc+1,high); /*对大于轴值序列实现递归排序*/ } return S; } //简单选择排序 void SelectSort(SqList *S) { int i,j,t;DataType tmp; for(i=1;i { for(j=i+1,t=i;j<=S->length;j++) { /* 在i开始的length-i+1条待排序记录中选关键字最小的记录 */ if (S->r[t].key>S->r[j].key) t=j; /* t中存放关键字最小的记录下标 */ } tmp=S->r[t]; S->r[t]=S->r[i]; S->r[i]=tmp; /* 关键字最小的记录与第i条记录交换 */ } for(i=1;i<=S->length;i++) printf("%d ",S->r[i].key); printf("不稳定"); } //合并排序 void Merge(DataType r[],DataType rf[],int u,int v,int t) { int i,j,k; for(i=u,j=v+1,k=u;i<=v&&j<=t;k++) { if(r[i].key<=r[i].key) rf[k]=r[i];i++; } else { rf[k]=r[j];j++; } } while(i<=v){rf[k++]=r[i++];} while(j<=t){rf[k++]=r[j++];} } void MSort(DataType p[],DataType p1[],int n,int t) { /* 将p[n…t]归并排序为p1[n…t] */ int m; DataType p2[MAXSIZE +1]; /*中间变量,存放部分排序结果*/ if (n==t) p1[n]=p[n]; /* p中只有一个元素,不需要进行归并操作 */ else { m=(n+t)/2; /*平分待排序的序列*/ MSort(p,p2,n,m); MSort(p,p2,m+1,t); Merge(p2,p1,n,m,t); } } void MergeSort(SqList *S) { /*对顺序表S作归并排序*/ int i; MSort(S->r,S->r,1,S->length); for(i=1;i<=S->length;i++) printf("%d ",S->r[i].key); printf("稳定"); } //主函数测试 void main() { //将顺序表中插入数据 SqList s;int a[11]={0,20,14,10,42,37,64,6,7,24,10};int gap[3]={5,3,1}; int i;int k;SqList *S; s.length=0; for(i=1;i<=10;i++) { s.r[i].key=a[i]; //插入元素,顺序表长度++ s.length++; } printf("下面为本程序的功能 129074157 刘伟开发\n"); printf("--------------------------\n"); printf("0:退出程序\n"); printf("1:直接插入排序\n"); printf("2:折半插入排序\n"); printf("3:shell排序\n"); printf("4:冒泡排序\n"); printf("--------------------------\n"); while(1) { scanf("%d",&k); switch(k) { case 0:exit(0);break; case 1: printf("直接插入排序 ");StraightInsertSort(&s);printf("\n");break; case 2: printf("折半插入排序 ");BinaryInsertSort(&s);printf("\n");break; case 3: printf("shell排序 ");ShellSort(&s,gap,3);printf("\n");break; case 4:printf("冒泡排序 "); BubbleSort(&s);printf("\n");break; case 5:printf("快速排序 "); { S=QuickSort(&s,1,10); for(i=1;i<=S->length;i++) printf("%d ",S->r[i].key); printf("不稳定"); printf("\n");break; } case 6:printf("简单选择排序 ");SelectSort(&s);printf("\n");break; case 7: printf("归并排序 ");MergeSort(&s);printf("\n");break; default:printf("输入数字错误\n"); } } } 运行效果: 实验总结: SqList s;s.length=0; for(i=1;i<=10;i++) { s.r[i].key=a[i]; //插入元素,顺序表长度++ s.length++; } 另外定义SqList s;不能定义*s;传到子函数中,传递的是地址&s,因为SqList *s是子函数的形参 排序算法 一、插入排序(Insertion Sort) 1. 基本思想: 每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。 2. 排序过程: 【示例】: [初始关键字] [49] 38 65 97 76 13 27 49 J=2(38) [38 49] 65 97 76 13 27 49 J=3(65) [38 49 65] 97 76 13 27 49 J=4(97) [38 49 65 97] 76 13 27 49 J=5(76) [38 49 65 76 97] 13 27 49 J=6(13) [13 38 49 65 76 97] 27 49 J=7(27) [13 27 38 49 65 76 97] 49 J=8(49) [13 27 38 49 49 65 76 97] Procedure InsertSort(Var R : FileType); //对R[1..N]按递增序进行插入排序, R[0]是监视哨// Begin for I := 2 To N Do //依次插入R[2],...,R[n]// begin R[0] := R[I]; J := I - 1; While R[0] < R[J] Do //查找R[I]的插入位置// begin R[J+1] := R[J]; //将大于R[I]的元素后移// J := J - 1 end R[J + 1] := R[0] ; //插入R[I] // end End; //InsertSort // 二、选择排序 1. 基本思想: 每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。 2. 排序过程: 【示例】: 初始关键字[49 38 65 97 76 13 27 49] 第一趟排序后13 [38 65 97 76 49 27 49] 第二趟排序后13 27 [65 97 76 49 38 49] 第三趟排序后13 27 38 [97 76 49 65 49] 第四趟排序后13 27 38 49 [49 97 65 76] 第五趟排序后13 27 38 49 49 [97 97 76] 《数据结构》实验报告排序实验题目: 输入十个数,从插入排序,快速排序,选择排序三类算法中各选一种编程实现。 实验所使用的数据结构内容及编程思路: 1. 插入排序:直接插入排序的基本操作是,将一个记录到已排好序的有序表中,从而得到一个新的,记录增一得有序表。 一般情况下,第i 趟直接插入排序的操作为:在含有i-1 个记录的有序子序列r[1..i-1 ]中插入一个记录r[i ]后,变成含有i 个记录的有序子序列r[1..i ];并且,和顺序查找类似,为了在查找插入位置的过程中避免数组下标出界,在r [0]处设置哨兵。在自i-1 起往前搜索的过程中,可以同时后移记录。整个排序过程为进行n-1 趟插入,即:先将序列中的第一个记录看成是一个有序的子序列,然后从第2 个记录起逐个进行插入,直至整个序列变成按关键字非递减有序序列为止。 2. 快速排序:基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 假设待排序的序列为{L.r[s] ,L.r[s+1],…L.r[t]}, 首先任意选取一个记录 (通常可选第一个记录L.r[s])作为枢轴(或支点)(PiVOt ),然后按下述原则重新排列其余记录:将所有关键字较它小的记录都安置在它的位置之前,将所有关键字较大的记录都安置在它的位置之后。由此可以该“枢轴”记录最后所罗的位置i 作为界线,将序列{L.r[s] ,… ,L.r[t]} 分割成两个子序列{L.r[i+1],L.[i+2], …,L.r[t]}。这个过程称为一趟快速排序,或一次划分。 一趟快速排序的具体做法是:附设两个指针lOw 和high ,他们的初值分别为lOw 和high ,设枢轴记录的关键字为PiVOtkey ,则首先从high 所指位置起向前搜索找到第一个关键字小于PiVOtkey 的记录和枢轴记录互相交换,然后从lOw 所指位置起向后搜索,找到第一个关键字大于PiVOtkey 的记录和枢轴记录互相 交换,重复这两不直至low=high 为止。 具体实现上述算法是,每交换一对记录需进行3 次记录移动(赋值)的操作。而实际上, 《几种排序算法的分析》 摘要: 排序算法是在C++中经常要用到的一种重要的算法。如何进行排序,特别是高效率的排序是是计算机应用中的一个重要课题。同一个问题可以构造不同的算法,最终选择哪一个好呢?这涉及如何评价一个算法好坏的问题,算法分析就是评估算法所消耗资源的方法。可以对同一问题的不同算法的代价加以比较,也可以由算法设计者根据算法分析判断一种算法在实现时是否会遇到资源限制的问题。排序的目的之一就是方便数据的查找。在实际生活中,应根据具体情况悬着适当的算法。一般的,对于反复使用的程序,应选取时间短的算法;对于涉及数据量较大,存储空间较小的情况则应选取节约存储空间的算法。本论文重点讨论时间复杂度。时间复杂度就是一个算法所消耗的时间。算法的效率指的是最坏情况下的算法效率。 排序分为内部排序和外部排序。本课程结业论文就内部排序算法(插入排序,选择排序,交换排序,归并排序和基数排序)的基本思想,排序步骤和实现算法等进行介绍。 本论文以较为详细的文字说明,表格对比,例子阐述等方面加以比较和总结,通过在参加数据的规模,记录说带的信息量大小,对排序稳定的要求,关键字的分布情况以及算法的时间复杂度和空间复杂度等方面进行比较,得出它们的优缺点和不足,从而加深了对它们的认识和了解,进而使自己在以后的学习和应用中能够更好的运用。 1.五种排序算法的实例: 1.1.插入排序 1.1.1.直接插入排序 思路:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。 要点:设立哨兵,作为临时存储和判断数组边界之用。 实现: Void InsertSort(Node L[],int length) { Int i,j;//分别为有序区和无序区指针 for(i=1;i 各种排序算法的总结和比较 1 快速排序(QuickSort) 快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。 (1)如果不多于1个数据,直接返回。 (2)一般选择序列最左边的值作为支点数据。(3)将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。 (4)对两边利用递归排序数列。 快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。 2 归并排序(MergeSort) 归并排序先分解要排序的序列,从1分成2,2分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个额外的数组。 3 堆排序(HeapSort) 堆排序适合于数据量非常大的场合(百万数据)。 堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。 堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。 Shell排序通过将数据分成不同的组,先对每一组进行排序,然后再对所有的元素进行一次插入排序,以减少数据交换和移动的次数。平均效率是O(nlogn)。其中分组的合理性会对算法产生重要的影响。现在多用D.E.Knuth的分组方法。 Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相对比较简单,它适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。 5 插入排序(InsertSort) 插入排序通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。插入排序是对冒泡排序的改进。它比冒泡排序快2倍。一般不用在数据大于1000的场合下使用插入排序,或者重复排序超过200数据项的序列。 电子科技大学实验报告 课程名称:数据结构与算法 学生姓名: 学号: 点名序号: 指导教师: 实验地点:基础实验大楼 实验时间: 5月20日 2014-2015-2学期 信息与软件工程学院各种排序算法比较
《数据结构》实验报告——排序.docx
几种排序算法分析
各种排序算法的总结和比较
实验报告-排序与查找