数据结构排序

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

数据结构课程的内容10.1概述10.2插入排序10.3交换排序10.4选择排序10.5归并排序10.6基数排序第10章内部排序10.1概述1.什么是排序?将一组杂乱无章的数据按一定的规律顺次排列起来。2.排序的目的是什么?存放在数据表中按关键字排序——便于查找!10.1概述3.排序算法的好坏如何衡量?•时间效率——排序速度(即排序所花费的全部比较次数)•空间效率——占内存辅助空间的大小若排序算法所需的辅助空间不依赖问题的规模n,即空间复杂度是O(1),则称排序方法是就地排序,否则是非就地排序。•稳定性——若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。4.什么叫内部排序?什么叫外部排序?——若待排序记录都在内存中,称为内部排序;内部排序基本操作有两种:◆比较两个关键字的大小;(比不可少的操作)◆存储位置的移动。——若待排序记录一部分在内存,一部分在外存,则称为外部排序。注:外部排序时,要将数据分批调入内存来排序,中间结果还要及时放入外存,显然外部排序要复杂得多。5.待排序记录在内存中怎样存储和处理?处理方式:①顺序排序——数据间的逻辑顺序关系通过其物理存储位置的相邻来体现,排序时直接移动记录;适合数据较少的情况!②链表排序——数据间的逻辑顺序关系通过结点中的指针体现,排序时只修改指针,不移动数据;③地址排序——数据存储在一段连续地址的空间,构造一个辅助表保持各数据的存放地址(指针),排序时先修改辅助表中的地址,最后再移动记录。②③适合数据较多的情况!注:大多数排序算法都是针对顺序表结构的(便于直接移动元素)6.顺序存储(顺序表)的抽象数据类型如何表示?Typedefstruct{//定义每个记录(数据元素)的结构KeyTypekey;//关键字InfoTypeotherinfo;//其它数据项}RecordType;Typedefstruct{//定义顺序表的结构RecordTyper[MAXSIZE+1];//存储顺序表的向量//r[0]一般作哨兵或缓冲区intlength;//顺序表的长度}SqList;#defineMAXSIZE20//设记录不超过20个typedefintKeyType;//设关键字为整型量(int型)7.内部排序的算法有哪些?——按排序的规则不同,可分为5类:•插入排序•交换排序(重点是快速排序)•选择排序•归并排序•基数排序d=关键字的位数(长度)——按排序算法的时间复杂度不同,可分为3类:•简单的排序算法:时间效率低,O(n2)•先进的排序算法:时间效率高,O(nlog2n)•基数排序算法:时间效率高,O(d×n)10.2插入排序插入排序的基本思想是:插入排序有多种具体实现算法:1)直接插入排序2)折半插入排序3)2路插入排序4)希尔排序每步将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。简言之,边插入边排序,保证子序列中随时都是排好序的。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】在已形成的有序表中线性查找,并在适当位置插入,把原来位置上的元素向后顺移。最简单的排序法!例2:关键字序列T=(21,25,49,25*,16,08),请写出直接插入排序的具体实现过程。*表示后一个25i=121254925*16080123456暂存21i=2i=3i=5i=4i=625252549494925*25*49161625*080849解:假设该序列已存入一维数组V[7]中,将V[0]作为缓冲或暂存单元(Temp)。则程序执行过程为:21254925*21初态:164925*25211608完成!时间效率:O(n2)——因为在最坏情况下,所有元素的比较次数总和为(0+1+…+n-1)→O(n2)。其他情况下还要加上移动元素的次数。空间效率:O(1)——因为仅占用1个缓冲单元算法的稳定性:稳定——因为25*排序后仍然在25的后面。对应程序参见教材P265。VoidInsertSort(SqList&L){//对顺序表L做直接插入排序for(i=2;i=L.length;++i)if(LT(L.r[i].key,L.r[i-1].key))//““,需将L.r[i]插入有序子表{L.r[0]=L.r[i];//复制为哨兵L.r[i]=L.r[i-1];for(j=i-2;LT(L.r[0].key,L.r[i].key);--j)L.r[j+1]=L.r[j];//记录后移L.r[j+1]=L.r[0];//插入到正确位置}}//InsertSort不需要增加辅助空间若设待排序的对象个数为n,则算法需要进行n-1次插入。最好情况下,排序前对象已经按关键码大小从小到大有序,每趟只需与前面的有序对象序列的最后一个对象的关键码比较1次,对象不需要移动。因此,总的关键码比较次数为n-1。直接插入排序的算法分析•最坏情况下,第i趟插入时,第i个对象必须与前面i-1个对象都做关键码比较,并且每做1次比较就要做1次数据移动。则总的关键码比较次数KCN和对象移动次数RMN分别为nininnniRMNnn2)niKCN2222141221//))(()(,//)((22•若待排序对象序列中出现各种可能排列的概率相同,则可取上述最好情况和最坏情况的平均情况。在平均情况下的关键码比较次数和对象移动次数约为n2/4。因此,直接插入排序的时间复杂度为o(n2)。•直接插入排序是一种稳定的排序方法。2)折半插入排序优点:比较的次数大大减少。时间效率:虽然比较次数大大减少,可惜移动次数并未减少,所以排序效率仍为O(n2)。空间效率:O(1)稳定性:稳定对应程序见教材P267(仅用于顺序表)新元素插入到哪里?在已形成的有序表中折半查找,并在适当位置插入,把原来位置上的元素向后顺移。VoidBInsertSort(SqList&L)//折半插入排序{for(i=2;i=L.length;++i){L.r[0]=L.r[i];//将L.r[i]暂存到L.r[0]low=1;high=i-1;while(low=high)//比较,折半查找插入位置{m=(low+high)/2;//折半if(LT(L.r[0].key,L.r[m].key))high=m-1;//插入点在低半区elselow=m+1;//插入点在高半区}//whilefor(j=i-1;j=high+1;--j)L.r[j+1]=L.r[j];//记录后移L.r[high+1]=L.r[0];//插入}//for}//BInsertSort30137085394262001234567813301370853942620012345678LHM初始i=213301370853942620012345678HLMi=213303070853942620012345678Hji=213133070853942620012345678Hji=230137085394262001234567820613303942708520012345678LMH初始i=8i=8i=820613303942708520012345678LMH20613303942708520012345678LHM30137085394262001234567820613303942708520012345678HLM初始i=8i=8i=820613303942708520012345678Hj20613303942708585012345678Hji=820613303942707085012345678Hj301370853942620012345678初始i=820613303939427085012345678Hji=820613303039427085012345678Hji=820613203939427085012345678Hji=820613303942427085012345678Hj折半插入排序的算法分析•折半查找比顺序查找快,所以折半插入排序就平均性能来说比直接插入排序要快。•在插入第i个对象时,需要经过log2i+1次关键码比较,才能确定它应插入的位置。•折半插入排序是一个稳定的排序方法。讨论:若记录是链表结构,用直接插入排序行否?折半插入排序呢?答:直接插入不仅可行,而且还无需移动元素,时间效率更高!但链表无法“折半”!折半插入排序的改进——2-路插入排序见教材P267。(1)基本思想:P267(2)举例:P268图10.2(3)算法分析:移动记录的次数约为n2/82-路插入排序只能减少移动记录的次数,而不能绝对避免移动记录。实现是借助循环向量。=若希望在排序过程中不移动记录,只有改变存储结构,进行表插入排序。4)希尔(shell)排序(又称缩小增量排序)基本思想:先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。技巧:子序列的构成不是简单地“逐段分割”,而是将相隔某个增量dk的记录组成一个子序列,让增量dk逐趟缩短(例如依次取5,3,1),直到dk=1为止。优点:让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。38例:关键字序列T=(49,38,65,97,76,13,27,49*,55,04),请写出希尔排序的具体实现过程。0123456789104938659776132749*5504初态:第1趟(dk=5)第2趟(dk=3)第3趟(dk=1)4913134938276549*9755760427386549*9755135576045513270427044949*4949*76387665659797551327044949*3876659713270449*7697算法分析:开始时dk的值较大,子序列中的对象较少,排序速度较快;随着排序进展,dk值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。r[i]voidShellSort(SqList&L,intdlta[],intt){//按增量序列dlta[0…t-1]对顺序表L作Shell排序for(k=0;kt;++k)ShellSort(L,dlta[k]);//增量为dlta[k]的一趟插入排序}//ShellSort时间效率:空间效率:O(1)——因为仅占用1个缓冲单元算法的稳定性:不稳定——因为49*排序后却到了49的前面希尔排序算法(主程序)参见教材P272O(n1.25)~O(1.6n1.25)——经验公式dk值依次装在dlta[t]中附:希尔排序算法分析对特定的待排序对象序列,可以准确地估算关键码的比较次数和对象移动次数。但想要弄清关键码比较次数和对象移动次数与增量选择之间的依赖关系,并给出完整的数学分析,还没有人能够做到。Knuth利用大量的实验统计资料得出,当n很大时,关键码平均比较次数和对象平均移动次数大约在n1.25到1.6n1.25的范围内。这是在利用直接插入排序作为子序列排序方法的情况下得到的。voidShellInsert(SqList&L,intdk){for(i=dk+1;i=L.length;++i)if(r[i].keyr[i-dk].key){r[0]=r[i];for(j=i-dk;j0&&(r[0].keyr[j].key

1 / 82
下载文档,编辑使用

©2015-2020 m.111doc.com 三一刀客.

备案号:赣ICP备18015867号-1 客服联系 QQ:2149211541

×
保存成功