课程设计说明书课程名称:数据结构和算法设计题目:多种排序院系:计算机科学与信息工程学院学生:学号:专业班级:计科嵌入式(12-1)指导教师:年月日课程设计任务书多种排序摘要:排序是算法中最基础的问题之一,经典的排序算法是前人不断总结得到的,基于比较的方法是比较直观的方式,主要存在插入法排序、堆排序、希尔排序、归并排序、快速排序,每一种排序算法都有自己的优缺点,比如插入法排序适用于那些长度短的排序,要是长的话,有些爱莫能助啦,堆排序主要是依据了二叉堆的特性,但是创建堆的过程也是一个复杂的问题,希尔排序的过程是一个不断精确的过程,但是目前也只是一个经验方式。
归并排序是一个递归的问题,采用分治的思想实现,但是这种算法需要额外的存储空间,快速排序虽然是实践中比较常用的算法,但是对于有序的数组采用快速排序就是灾难。
比较型算法的时间复杂度最优也只能到达O(NlogN)。
关键词:归并排序快排排序选择排序冒泡排序插入排序堆排序希尔排序部排序目录1. 设计背景 (4)1.1问题描述 (4)1.2 问题分析 (4)2.设计方案 (4)2.1 算法设计 (4)2.2 功能模块分析 (6)3.主要算法流程图 (15)4. 结果与结论 (16)4.1正确结果 (16)4.2错误信息 (18)5. 算法复杂度以及稳定性分析 (18)6. 收获与致 (18)7. 参考文献 (19)8. 附件 (20)1. 设计背景1.1问题描述利用随机函数产生N个随机整数(10000以上),对这些数进行多种方法进行排序。
包括:插入排序、希尔排序、起泡排序、快速排序、选择排序、堆排序、归并排序。
1.2 问题分析经典的排序算法是前人不断总结得到的,基于比较的方法是比较直观的方式,主要存在插入法排序、堆排序、希尔排序、归并排序、快速排序,每一种排序算法都有自己的优缺点。
2.设计方案2.1 算法设计(1)选择排序在待排序的一组数据元素中,选出最小的一个数据元素与第一个位置的数据元素交换;然后在剩下的数据元素当中再找最小的与第二个位置的数据元素交换,循环到只剩下最后一个数据元素为止。
(2)冒泡排序相邻的两个元素进行比较,将小的调到前面,大的调到后面。
(3)插入排序待排序的记录放在数组R[0…n-1]中排序过程中某一时刻,R被划分成两个子区间R[0,i-1] (有序和)R[i…n-1](无序)。
直接插入的基本操作是将当前无序区的一个记录R[i]插入到有序区R[0…i-1]中适当的位置(4)快速排序在待排序的数组的n个元素中取一个元素(一般取第一个),将其移动到这样的位置:在其之前的元素的值都小于它,在其之后的元素都大于它,这样是一趟快速排序;然后对数组的两个部分进行同样的操作,直到每部分只有一个记录为止;总之,每趟使表的第一个元素放在适当位置,将表两分,再对两子表进行同样的递归划分,直至划分的子表长度为1。
(5)堆排序堆排序中 heap 算法的时间复杂度与堆所对应的完全二叉树的树高度 log2n 相关。
而heapsort 中对heap 的调用数量级为n,所以堆排序的整个时间复杂度为O(nlog2n) 。
并且堆排序是不稳定的。
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(6)归并排序将两个或两个以上的有序表组成一个新的有序表。
(7)希尔排序将无序数组分割为若干个子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,对各个子序列进行插入排序;然后再选择一个更小的增量,再将数组分割为多个子序列进行排序......最后选择增量为1,即使用直接插入排序,使最终数组成为有序。
增量的选择:在每趟的排序过程都有一个增量,至少满足一个规则增量关系 d[1] > d[2] > d[3] >..> d[t] = 1 (t趟排序);根据增量序列的选取其时间复杂度也会有变化,这个不少论文进行了研究,在此处就不再深究;本文采用首选增量为n/2,以此递推,每次增量为原先的1/2,直到增量为1。
2.2 功能模块分析1.数据输入:采取随机函数实现输入数据表。
int input_num(){printf("您要给多少个数排序?\n\t\t");scanf("%d",&data_num);srand(NULL);printf("随机产生%d个数:\n\t\t",data_num);for(int i=1;i<=data_num;i++){data_array[i]=rand()%10000000;printf("%d\n",data_array[i]);old[i]=data_array[i];printf("\n\t\t");}}2.数据输出:for循环输出即可。
int outnew0(){printf("排序后的结果为:");for(int i=data_num;i>=1;i--)printf("%d%s",data_array[i],i!=1?" ":"\n");}其中增加了输出空格与换行区别。
printf("DATE:May twenty 2014\n");printf("All Copyright Reserved 2014-2015 Wang Guangchun \n");printf("ADDRESS: 604 AYIT\r\n\n\n");printf("——————————————————— \n");printf("——————各种排序比较————————— \n");printf("默认从大到小输出,可以选择9进行切换\n");printf("——————————————————— \n");printf(" * * \n");printf(" * * * \n");printf(" * * \n");printf(" * 520 * \n");printf(" * 欢迎 * \n");printf(" * 使用 * \n");printf(" * * \n");printf(" * \n");printf("欢迎再次使用!!!\n\r\n");printf("*******************************************\n");printf("** . ..... . . ..... **\n");printf("** . . . . . . **\n");printf("** . . . . . ..... **\n");printf("** . . . . . . **\n");printf("** ..... ..... . ..... **\n");printf("*******************************************\n");printf("\n——————————————————— \n");printf("——————请输入指令———————— \n");printf("————********************————— \n");printf("————$ 1.快速排序 $————— \n");printf("————$ 2.归并排序 $————— \n");printf("————$ 3.堆排序 $————— \n");printf("————$ 4.希尔排序 $————— \n");printf("————$ 5.插入排序 $————— \n");printf("————$ 6.选择排序 $————— \n");printf("————$ 7.冒泡排序 $————— \n");printf("————$ 8.重新随机输入 $————— \n");printf("————$ 9.选择排序方式 $————— \n");printf("————********************————— \n");printf("————— 0.退出—————— \n");printf("——————————————————— \n");printf("请选择:\n");printf("——————请输入指令———————— \n");printf("————********************————— \n");printf("————$ 1.从小到大 $————— \n");printf("————$ 0.从大到小 $————— \n");printf("————********************————— \n");printf("————— 87.退出—————— \n");printf("——————————————————— \n");printf("请选择:\n");5.排序方法的实现:(1)选择排序void chose_sort(int a[],int n){int min,temp;for(int i=0;i<n;i++){min=i;for(int j=i;j<n;j++)if(a[min]>a[j])min=j;temp=a[min];a[min]=a[i];a[i]=temp;}}(2)希尔排序void ShellInsert(int *a,int d,int n){for (int i=d;i<n;i++)//从第2个数据开始插入{int j=i-d;int temp=a[i];//记录要插入的数据while(j >= 0&&a[j]>temp)//从后向前,找到比其小的数的位置{a[j+d]=a[j];//向后挪动j-=d;}if(j!=i-d)//存在比其小的数a[j+d]=temp;}}void ShellSort(int* a,int n){int d=n/2;//初始增量设为数组长度的一半while(d>=1){ShellInsert(a,d,n);d=d/2;//每次增量变为上次的二分之一}}(3)归并排序:void __merge(int a[],int first,int mid,int last,int temp[]) {int i=first,j=mid+1,m=mid,n=last,k=0;while(i<=m&&j<=n){if(a[i]<=a[j])temp[k++]=a[i++];elsetemp[k++]=a[j++];}while(i<=m)temp[k++]=a[i++];while(j<=n)temp[k++]=a[j++];for(i=0;i<k;i++)a[first+i]=temp[i];}void MergeSort(int a[],int first,int last,int temp[]) {if(first<last){int mid=(first+last)/2;MergeSort(a,first,mid,temp);MergeSort(a,mid+1,last,temp);__merge(a,first,mid,last,temp);}}bool MergeSort(int a[],int n){int *p=new int[n];if(p==NULL)return false;else{MergeSort(a,0,n-1,p);delete[] p;return true;}}(4)堆排序:void HeapAdjust(int *a,int i,int size)//调整堆{int lchild=2*i;//i的左孩子节点序号int rchild=2*i+1;//i的右孩子节点序号int max=i;//临时变量if(i<=size/2)//如果i是叶节点就不用进行调整{if(lchild<=size&&a[lchild]>a[max])max=lchild;if(rchild<=size&&a[rchild]>a[max])max=rchild;if(max!=i){swap(a[i],a[max]);HeapAdjust(a,max,size);//避免调整之后以max为父节点的子树不是堆 }}}void BuildHeap(int *a,int size)//建立堆{int i;for(i=size/2;i>=1;i--)//非叶节点最大序号值为size/2HeapAdjust(a,i,size);}void HeapSort(int *a,int size)//堆排序{int j=1;BuildHeap(a,size);for(int i=size;i>=1;i--){swap(a[1],a[i]); //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面//BuildHeap(a,i-1); //将余下元素重新建立为大顶堆HeapAdjust(a,1,i-1); //重新调整堆顶节点成为大顶堆}}(5)冒泡排序:void maopao(){int temp;for(int i=1;i<=data_num;i++)for(int j=i+1;j<=data_num;j++)if(data_array[i]>data_array[j]){temp=data_array[i];data_array[i]=data_array[j];data_array[j]=temp;}}(6)插入排序:void charu(){int i,j;int temp;printf("插入排序:\n");for(i=1;i<=data_num;i++){int temp=data_array[i];for (j=i;j>0 && temp<data_array[j-1];j--){data_array[j]=data_array[j-1];}data_array[j]=temp;}if(!t)outnew0();elseoutnew1();}(7)快速排序:void kuaisu1()//快速排序1{printf("快速排序:\n");sort(data_array+1,data_array+data_num+1); if(!t)outnew0();elseoutnew1();}3.主要算法流程图4. 结果与结论4.1 正确结果1.主界面人机交互3.选择排序方式4.输出结果4.2错误信息5.算法复杂度以及稳定性分析下图反映了不同算法排序的时间复杂度的级别及其空间复杂度和稳定性。