内部排序实验报告_第1页
内部排序实验报告_第2页
内部排序实验报告_第3页
内部排序实验报告_第4页
内部排序实验报告_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、数据结构实验报告内部排序班级: 13 软 工 一 班 学号: 13131113 姓名: 吕 蒙学号: 13131116 姓名: 钱剑滨学号: 13131142 姓名: 孔亚亚学号: 13131144 姓名: 邱佃雨 13软工转本1 钱剑滨 实验报告内部排序实验报告 信息工程 系 13软工转本1 日期 2016年06月07日 一、 实验内容编写程序实现各种内部排序(包括:冒泡排序、插入排序、选择排序、希尔排序、快速排序、堆排序、归并排序、基数排序),并运用这些排序对一组随机生成的数组进行排序。二、 时间复杂度1 冒泡排序(O(n2)若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较

2、次数和记录移动次数均达到最小值:,。所以,冒泡排序最好的时间复杂度为。若初始文件是反序的,需要进行趟排序。每趟排序要进行次关键字的比较(1in-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:冒泡排序的最坏时间复杂度为。综上,因此冒泡排序总的平均时间复杂度为。2 插入排序(O(n2)如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作

3、的次数加上 (n-1)次。平均来说插入排序算法的时间复杂度为O(n2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。3 选择排序(O(n2)选择排序的交换操作介于 0 和 (n - 1) 次之间。选择排序的比较操作为 n (n - 1) / 2 次之间。选择排序的赋值操作介于 0 和 3 (n - 1) 次之间。比较次数O(n2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+.+1=n*(n-1)/2。交换次数O(n),最好情况是,已经有序,交换0次;最坏情况交换n-1次,逆序交换

4、n/2次。交换次数比冒泡排序少多了,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。4 希尔排序希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n2)好一些。5 快速排序(O(n2)无论适用哪一种方法来选择pivot,由于我们不知道各个元素间的相对大小关系(若知道就已经排好序了),所以我们无法确定pivot的选择对划分造成的影响。因此对各种pivot选择法而言,最坏情况和最好情况都是相同的。我们从直觉

5、上可以判断出最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候(设输入的表有n个元素)。下面我们暂时认为该猜测正确,在后文我们再详细证明该猜测。对于有n个元素的表Lp.r,由于函数Partition的计算时间为(n),所以快速排序在序坏情况下的复杂性有递归式如下:T(1)=(1),T(n)=T(n-1)+T(1)+(n) (1)用迭代法可以解出上式的解为T(n)=(n2)。这个最坏情况运行时间与插入排序是一样的。下面我们来证明这种每次划分过程产生的两个区间分别包含n-1个元素和1个元素的情况就是最坏情况。设T(n)是过程Quick_Sort作用于规模为n的输入上的最坏

6、情况的时间,则T(n)=max(T(q)+T(n-q)+(n),其中1qn-1 (2)我们假设对于任何kn,总有T(k)ck,其中c为常数;显然当k=1时是成立的。将归纳假设代入(2),得到:T(n)max(cq2+c(n-q)2)+(n)=c*max(q2+(n-q)2)+(n)因为在1,n-1上q2+(n-q)2关于q递减,所以当q=1时q2+(n-q)2有最大值n2-2(n-1)。于是有:T(n)cn2-2c(n-1)+(n)cn2只要c足够大,上面的第二个小于等于号就可以成立。于是对于所有的n都有T(n)cn。这样,排序算法的最坏情况运行时间为(n2),且最坏情况发生在每次划分过程产生

7、的两个区间分别包含n-1个元素和1个元素的时候。时间复杂度为o(n2)。6 堆排序(O(nlgn))堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,所以堆排序的时间复杂度是O(nlgn)7 归并排序(O(nlgn))时间复杂度为O(nlogn) 这是该算法中最好、最坏和平均的时间性能。空间复杂度为 O(n)比较操作的次数介于(nlogn) / 2和nlogn - n + 1。赋值操作的次数是(2nlogn)。归并算法的空间复杂度为:0 (n)归并排序比较占用内存,但却是一种效率高且稳定的算法。8 基数排序(O(d(

8、n+radix))时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集。 空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。三、 算法稳定性1. 冒泡排序(稳定)冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来

9、,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。2. 插入排序(稳定)插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。3. 选择排序(不稳定)选择排序是给每个位置选择当前元素

10、最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。4. 希尔排序(不稳定)由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排

11、序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。5. 快速排序(不稳定)快速排序有两个方向,左边的i下标一直往右走,当ai acenter_index。如果i和j都走不动了, i j。交换aj和acenter_index,完成一趟快速排序。在中枢元素和aj交换的时候,很有可能把前面的元素的稳定性打乱,比如序列5 3 3 4 3 8 9 10 11,现在中枢元素5和3(第5个元素,下标从1开始计)交换就会把元素3的稳定性打乱,所以快速排序是一个不稳定的排序算法,不稳定发生在中枢元素和aj交换的时刻。6. 堆排序(不稳定)堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销

12、构成,它们均是通过调用Heapify实现的。堆排序的最坏时间复杂度为O(nlgn)。堆排序的平均性能较接近于最坏性能。由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。堆排序是就地排序,辅助空间为O(1),它是不稳定的排序方法。7. 归并排序(稳定)归并排序是一种稳定的排序8. 基数排序(稳定)基数排序是一种稳定的排序四、 各排序介绍和算法实现1. 冒泡排序冒泡排序算法的运作如下:(从后往前)(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。(2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。(3)针对所有的元素重

13、复以上的步骤,除了最后一个。(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。代码:void maopao(int numberNMAX)int temp, i, j, t;yuan(numberN);int numberYMAX;for(t = 0; t N; t+)numberYt = numberNt;for(i = 0; i N - 1; i+)for(j = 0; j numberYj + 1)temp = numberYj;numberYj = numberYj + 1;numberYj + 1 = temp;sheng(numberY);2. 插入排序一

14、般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:(1)从第一个元素开始,该元素可以认为已经被排序(2)取出下一个元素,在已经排序的元素序列中从后向前扫描(3)如果该元素(已排序)大于新元素,将该元素移到下一位置(4)重复步骤3,直到找到已排序的元素小于或者等于新元素的位置(5)将新元素插入到下一位置中(6)重复步骤25代码:void charu(int numberNMAX) int i,j,t; int temp; int numberYMAX; yuan(numberN); for(t = 0; t N; t+)numberYt = numberNt; for(i=1

15、;i0&numberYj-1temp;j-) numberYj=numberYj-1; numberYj=temp; sheng(numberY);3. 选择排序对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第

16、二小的数,让他跟数组中第二个元素交换一下值,以此类推。代码:void xuanze(int numberNMAX)int temp, i, j, t, min;int numberYMAX;yuan(numberN);for(t = 0; t N; t+)numberYt = numberNt;for(i = 0; i N - 1; i+)min = i;for(j = i + 1; j numberYj)min = j;temp = numberYi;numberYi = numberYmin;numberYmin = temp;sheng(numberY);4. 希尔排序先取一个小于n的整

17、数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2d1重复上述的分组和排序,直至所取的增量dt=1(dtdt-ld2d1),即所有记录放在同一组中进行直接插入排序为止。代码:void xier(int numberNMAX) int d, i, j, t, temp; int numberYMAX; yuan(numberN); for(t = 0; t = 1;d = d/2) for(i = d; i = 0) & (numberYj temp);j = j-d) numberYj + d = n

18、umberYj; numberYj + d = temp; sheng(numberY);5. 快速排序设要排序的数组是A0AN-1,首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。一趟快速排序的算法是:(1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;(2)以第一个数组元素作为关键数据,赋值给key,即key=A0;(3)从j开始向前搜索,即由后开始向前搜索(j-),找到第一个

19、小于key的值Aj,将Aj和Ai互换;(4)从i开始向后搜索,即由前开始向后搜索(i+),找到第一个大于key的Ai,将Ai和Aj互换;(5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中Aj不小于key,4中Ai不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i=j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。代码:int partions(int numberYMAX,int low,int high)int prvotkey=numberYlow;while (lo

20、whigh) while (low=prvotkey) -high; numberYlow=numberYhigh; while (lowhigh&numberYlow=prvotkey) +low; numberYhigh=numberYlow;numberYlow=prvotkey;return low;void quicksort(int numberYMAX,int low,int high)int prvotloc;if(lowhigh) prvotloc=partions(numberY,low,high); /将第一次排序的结果作为枢轴 quicksort(numberY,low

21、,prvotloc-1); /递归调用排序 由low 到prvotloc-1 quicksort(numberY,prvotloc+1,high); /递归调用排序 由 prvotloc+1到 highvoid kuaisu(int numberNMAX)int i;int numberYMAX;yuan(numberN);for(i = 0; i N; i+)numberYi = numberNi;quicksort(numberY, 0, N-1);sheng(numberY);6. 堆排序大根堆排序算法的基本操作:(1)建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节

22、点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。(2)调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调

23、整的。(3)堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。代码:/ array是待调整的堆数组,i是待调整的数组元素的位置,nlength是数组的长度/本函数功能是:根据数组array构建大根堆代码:/ array是待调整的堆数组,i是待调整的数组元素的位置,nlength是数组的长度/本函数功能是:根据数组array构建大根堆代码:void HeapAdjust(int array, int i, int nLength) int

24、 nChild; int nTemp; for (nTemp = arrayi; 2 * i + 1 nLength; i = nChild) / 子结点的位置=2*(父结点位置)+ 1 nChild = 2 * i + 1; / 得到子结点中较大的结点 if ( nChild arraynChild) +nChild; / 如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点 if (nTemp arraynChild) arrayi = arraynChild; arraynChild= nTemp; else / 否则退出循环 break; / 堆排序算法void dui

25、(int numberNMAX) int tmp, t, i; int numberYMAX; yuan(numberN); for(t = 0; t = 0; -i) HeapAdjust(numberY, i, N); / 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素 for (i = N - 1; i 0; -i) / 把第一个元素和当前的最后一个元素交换, / 保证当前的最后一个位置的元素都是在现在的这个序列之中最大的 / Swap(&array0, &arrayi); tmp = numberYi; numberYi = numberY0; numberY0

26、= tmp; / 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值 HeapAdjust(numberY, 0, i); sheng(numberY);7. 归并排序归并操作的工作原理如下:(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列(2)设定两个指针,最初位置分别为两个已经排序序列的起始位置(3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置(4)重复步骤(3)直到某一指针超出序列尾(5)将另一序列剩下的所有元素直接复制到合并序列尾代码:/归并操作void Merge(int sourceArr, int

27、 targetArr, int startIndex, int midIndex, int endIndex) int i, j, k; for(i = midIndex+1, j = startIndex; startIndex = midIndex & i = endIndex; j+) if(sourceArrstartIndex sourceArri) targetArrj = sourceArrstartIndex+; else targetArrj = sourceArri+; if(startIndex = midIndex) for(k = 0; k = midIndex-st

28、artIndex; k+) targetArrj+k = sourceArrstartIndex+k; if(i = endIndex) for(k = 0; k = endIndex- i; k+) targetArrj+k = sourceArri+k; /内部使用递归,空间复杂度为n+lognvoid MergeSort(int sourceArr, int targetArr, int startIndex, int endIndex) int midIndex; int tempArrMAX; /此处大小依需求更改 if(startIndex = endIndex) targetArrstartIndex = sourceArrstartIndex; else midIndex = (startIndex + endIndex)/2; MergeSort(sourceArr, tempArr, s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论