您好,欢迎访问三七文档
第10章内部排序10.1概述10.2插入排序10.3快速排序10.4堆排序10.5归并排序10.6基数排序10.7各种排序方法的综合比较10.1概述一、排序的定义二、内部排序和外部排序三、内部排序方法的分类一、什么是排序?排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。例如:将下列关键字序列52,49,80,36,14,58,61,23,97,75调整为14,23,36,49,52,58,61,75,80,971.什么是排序?将一组杂乱无章的数据按一定的规律顺次排列起来。2.排序的目的是什么?存放在数据表中按关键字排序3.排序算法的好坏如何衡量?•时间效率——排序速度(即排序所花费的全部比较次数)•空间效率——占内存辅助空间的大小•稳定性——若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。——便于查找!二、内部排序和外部排序若待排序记录都在内存中,整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序;反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。三、内部排序的方法内部排序的过程是一个逐步扩大记录的有序序列长度的过程。经过一趟排序有序序列区无序序列区有序序列区无序序列区基于不同的“扩大”有序序列长度的方法,内部排序方法大致可分下列几种类型:插入类交换类选择类归并类基数排序待排记录的数据类型定义如下:#defineMAXSIZE1000//待排顺序表最大长度typedefintKeyType;//关键字类型为整数类型typedefstruct{KeyTypekey;//关键字项InfoTypeotherinfo;//其它数据项}RcdType;//记录类型typedefstruct{RcdTyper[MAXSIZE+1];//r[0]闲置intlength;//顺序表长度}SqList;//顺序表类型1.插入类将无序子序列中的一个或几个记录“插入”到有序序列中,从而增加记录的有序子序列的长度。2.交换类通过“交换”无序序列中的记录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。3.选择类从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。4.归并类通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度。10.2插入排序插入排序的基本思想是:每步将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。简言之,边插入边排序,保证子序列中随时都是排好序的有序序列R[1..i-1]R[i]无序序列R[i..n]一趟直接插入排序的基本思想:有序序列R[1..i]无序序列R[i+1..n]实现“一趟插入排序”可分三步进行:3.将R[i]插入(复制)到R[j+1]的位置上。2.将R[j+1..i-1]中的所有记录均后移一个位置;1.在R[1..i-1]中查找R[i]的插入位置,R[1..j].keyR[i].keyR[j+1..i-1].key;直接插入排序(基于顺序查找)表插入排序(基于链表存储)不同的具体实现方法导致不同的算法描述折半插入排序(基于折半查找)希尔排序(基于逐趟缩小增量)小改进大改进1)直接插入排序新元素插入到哪里?例1:关键字序列T=(13,6,3,31,9,27,5,11),请写出直接插入排序的中间过程序列。【13】,6,3,31,9,27,5,11【6,13】,3,31,9,27,5,11【3,6,13】,31,9,27,5,11【3,6,13,31】,9,27,5,11【3,6,9,13,31】,27,5,11【3,6,9,13,27,31】,5,11【3,5,6,9,13,27,31】,11【3,5,6,9,11,13,27,31】在已形成的有序表中线性查找,并在适当位置插入,把原来位置上的元素向后顺移。最简单的排序法!一、直接插入排序利用“顺序查找”实现“在R[1..i-1]中查找R[i]的插入位置”算法的实现要点:从R[i-1]起向前进行顺序查找,监视哨设置在R[0];R[0]=R[i];//设置“哨兵”循环结束表明R[i]的插入位置为j+1R[0]jR[i]for(j=i-1;R[0].keyR[j].key;--j);//从后往前找j=i-1插入位置对于在查找过程中找到的那些关键字不小于R[i].key的记录,并在查找的同时实现记录向后移动;for(j=i-1;R[0].keyR[j].key;--j)R[j+1]=R[j]R[0]jR[i]j=i-1上述循环结束后可以直接进行“插入”插入位置令i=2,3,…,n,实现整个序列的排序。for(i=2;i=n;++i)if(R[i].keyR[i-1].key){在R[1..i-1]中查找R[i]的插入位置;插入R[i];}voidInsertionSort(SqList&L){//对顺序表L作直接插入排序。for(i=2;i=L.length;++i)if(L.r[i].keyL.r[i-1].key){}}//InsertSortL.r[0]=L.r[i];//复制为监视哨for(j=i-1;L.r[0].keyL.r[j].key;--j)L.r[j+1]=L.r[j];//记录后移L.r[j+1]=L.r[0];//插入到正确位置例2:关键字序列T=(21,25,49,25*,16,08),请写出直接插入排序的具体实现过程。*表示后一个25i=121254925*16080123456哨兵21i=2i=3i=5i=4i=6254925*25*49161625*080849解:假设该序列已存入一维数组r[7]中,将r[0]作为哨兵(Temp)。则程序执行过程为:21254925*21初态:164925*25211608完成!时间效率:因为在最坏情况下,所有元素的比较次数总和为(0+1+…+n-1)→O(n2)。其他情况下也要考虑移动元素的次数。故时间复杂度为O(n2)空间效率:仅占用1个缓冲单元——O(1)算法的稳定性:因为25*排序后仍然在25的后面——稳定内部排序的时间分析:实现内部排序的基本操作有两个:(2)“移动”记录。(1)“比较”序列中两个关键字的大小;对于直接插入排序:最好的情况(关键字在记录序列中顺序有序):“比较”的次数:最坏的情况(关键字在记录序列中逆序有序):“比较”的次数:112nni02)1)(4()1(2nnini“移动”的次数:“移动”的次数:2)1)(2()(2nnini时间复杂度为O(n2)2)折半插入排序优点:比较次数大大减少,全部元素比较次数仅为O(nlog2n)。时间效率:虽然比较次数大大减少,可惜移动次数并未减少,所以排序效率仍为O(n2)。空间效率:仍为O(1)稳定性:稳定一个的改进方法:思考:折半插入排序还可以改进吗?能否减少移动次数?既然子表有序且为顺序存储结构,则插入时采用折半查找定可加速。3)希尔(shell)排序基本思想:先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。技巧:子序列的构成不是简单地“逐段分割”,而是将相隔某个增量dk的记录组成一个子序列,让增量dk逐趟缩短(例如依次取5,3,1),直到dk=1为止。优点:让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。又称缩小增量排序38例:关键字序列T=(49,38,65,97,76,13,27,49*,55,04),请写出希尔排序的具体实现过程(dk=5,3,1)。0123456789104938659776132749*5504初态:第1趟(dk=5)第2趟(dk=3)第3趟(dk=1)4913134938276549*9755760427386549*9755135576045513270427044949*4949*76387665659797551327044949*3876659713270449*7697算法分析:开始时dk的值较大,子序列中的对象较少,排序速度较快;随着排序进展,dk值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。r[i]时间效率:空间效率:O(1)——因为仅占用1个缓冲单元算法的稳定性:不稳定——因为49*排序后却到了49的前面O(n1.25)~O(1.6n1.25)——由经验公式得到10.3交换排序两两比较待排序记录的关键码,如果发生逆序(即排列顺序与排序后的次序正好相反),则交换之,直到所有记录都排好序为止。交换排序的主要算法有:1)冒泡排序2)快速排序交换排序的基本思想是:一、起泡排序二、一趟快速排序三、快速排序四、快速排序的时间分析一、起泡排序假设在排序过程中,记录序列R[1..n]的状态为:第i趟起泡排序无序序列R[1..n-i+1]有序序列R[n-i+2..n]n-i+1无序序列R[1..n-i]有序序列R[n-i+1..n]比较相邻记录,将关键字最大的记录交换到n-i+1的位置上1)冒泡排序基本思路:每趟不断将记录两两比较,并按“前小后大”(或“前大后小”)规则交换。优点:每趟结束时,能挤出一个最大值到最后面位置,一旦下趟没有交换发生,还可以提前结束排序。前提:顺序存储结构例:关键字序列T=(21,25,49,25*,16,08),请写出冒泡排序的具体实现过程。21,25,49,25*,16,0821,25,25*,16,08,4921,25,16,08,25*,4921,16,08,25,25*,4916,08,21,25,25*,4908,16,21,25,25*,49初态:第1趟第2趟第3趟第4趟第5趟voidBubbleSort(ElemR[],intn){while(i1){}//while}//BubbleSorti=n;i=lastExchangeIndex;//本趟进行过交换的//最后一个记录的位置if(R[j+1].keyR[j].key){Swap(R[j],R[j+1]);lastExchangeIndex=j;//记下进行交换的记录位置}//iffor(j=1;ji;j++)lastExchangeIndex=1;冒泡排序的算法分析•最好情况:初始排列已经有序,只执行一趟起泡,做n-1次关键码比较,不移动对象。•最坏情形:初始排列逆序,算法要执行n-1趟起泡,第i趟(1in)做了n-i次关键码比较,执行了n-i次对象交换。因此:时间效率:O(n2)—因为要考虑最坏情况空间效率:O(1)—只在交换时用到一个缓冲单元稳定性:稳定—25和25*在排序前后的次序未改变时间分析:最好的情况(关键字在记录序列中顺序有序):只需进行一趟起泡“比较”的次数:最坏的情况(关键字在记录序列中逆序有序):需进行n-1趟起泡“比较”的次数:0“移动”的次数:“移动”的次数:n-12)1()1(2nnini2)1(3)1(32nnini冒泡排序的优点:每一趟整理元素时,不仅可以完全确定一个元素的位置(挤出一个泡到表尾),一旦下趟没有交换发生,还可以提前结束排序。有没有比冒泡排序更快的算法?有!快速排序法——全球公认!因为它每趟都能准确定位不止1个元素!2)快速排序从待排序列中任取一个元素(例如取第一个)作为中心,所有比它小的元素一律前放,所有比它大的元素一律后放,形成左右两个子表;然后再对各子表重新选择中心元素并依此规则调整,直到每个子表的元素只剩一个。此时便为有序序列了。基本思想:优点:因为每趟可以确定不止一个元素的位置,而且呈指数增加,所以特别快!前提:顺序存储结构52498036145861972375stlowhi
本文标题:数据结构-排序
链接地址:https://www.777doc.com/doc-3221806 .html