收藏 分享(赏)

第9章内部排序.ppt

上传人:lxhqcj 文档编号:8467544 上传时间:2019-06-29 格式:PPT 页数:85 大小:2.01MB
下载 相关 举报
第9章内部排序.ppt_第1页
第1页 / 共85页
第9章内部排序.ppt_第2页
第2页 / 共85页
第9章内部排序.ppt_第3页
第3页 / 共85页
第9章内部排序.ppt_第4页
第4页 / 共85页
第9章内部排序.ppt_第5页
第5页 / 共85页
点击查看更多>>
资源描述

1、第9章 内部排序,数据结构课程的内容,主要内容,排序的基本概念及分类 插入排序 交换排序 选择排序 归并排序 基数排序 各种内部排序方法的比较讨论,重点与难点,本章的重点 直接插入排序 希尔排序 快速排序 堆排序 归并排序 链式基数排序 本章的难点 希尔排序算法 快速排序算法 堆排序算法,9.1 概述,排序(Sort):将一组杂乱无章的数据按一定的规律顺次排列起来。 假设含n个记录的序列为R1,R2,Rn (10-1)其相应的关键字序列为K1,K2,Kn,需确定1,2,n的一种排列p1,p2,pn,使其相应的 关键字满足如下的非递减(或非递增)关系: Kp1Kp2Kpn (10-2) 即使式(

2、10-1)的序列成为一个按关键字有序的序列:Rp1,Rp2,Rpn (10-3) 这样一种操作称为排序。,9.1 概述,数据表(Datalist):它是待排序数据对象的有限集合。 排序码(Key):通常数据对象有多个属性域, 即多个数据成员组成, 其中有一个属性域可用来区分对象, 作为排序依据。该域即为排序码。每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。 排序的目的便于查找。,9.1 概述,排序算法的衡量: 时间效率排序速度。排序的时间开销是衡量算法好坏的最重要的标志。排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。对于那些受对象排序码序列初始排列及对象个数影响较

3、大的,需要按最好情况和最坏情况进行估算。 空间效率占内存辅助空间的大小,评价算法好坏的另一种标准。 稳定性如果在对象序列中有两 个对象ri和rj, 它们的排序码 ki = kj , 且在排序之前, 对象ri排在rj前面。如果在排序之后, 对象ri仍在对象rj的前面, 则称这个排序方法是稳定的, 否则称这个排序方法是不稳定的。,9.1 概述,排序的分类 排序过程中涉及的存储器不同:内排序是指在排序期间数据对象全部存放在内存的排序;外排序是指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。 排序过程中依据的原则不同对内部排序进行分类:插入排序、

4、交换排序、选择排序、归并排序和计数排序。 按内部排序过程中所需的工作量来区分: 简单的排序方法,其时间复杂度为O(n2); 先进的排序方法,其时间复杂度为O(nlogn); 基数排序,其时间复杂度为O(dn)。,9.1 概述,待排序记录在内存中的存储和处理 顺序排序排序时直接移动记录; 链表排序排序时只移动指针; 地址排序排序时先移动地址,最后再移动记录。 地址排序中可以增设一维数组来专门存放记录的地址。 在排序过程中,一般进行两种基本操作: 比较两个关键字的大小; 将记录从一个位置移动到另一个位置。 对于第二种操作,需要采用适当地存储方式,即顺序结构、链表结构、地址结构。,9.1 概述,顺序

5、存储(顺序表)的抽象数据类型 #define MAXSIZE 20 /设记录不超过20个 typedef int KeyType ; /设关键字为整型量(int型)typedef struct /定义每个记录(数据元素)的结构 KeyType key ; /关键字 InfoType otherinfo; /其它数据项 RecordType ;Typedef struct /定义顺序表的结构 RecordType r MAXSIZE +1 ; /存储顺序表的向量 /r0一般作哨兵或缓冲区 int length ; /顺序表的长度 SqList ;,9.2 插入排序(Insert Sorting)

6、,插入排序的基本思想每步将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。 直接插入排序(Straight Insertion Sort) 折半插入排序(Binary Insertion Sort) 2-路插入排序 表插入排序 希尔排序(Shells Sort,Diminishing Increment Sort),9.2 插入排序直接插入排序,直接插入排序 在已形成的有序表中线性查找,并在适当位置插入,把原来位置上的元素向后顺移。 关键字序列T=(13,6,3,31,9,27,5,11),【13】, 6, 3, 31, 9, 27, 5,

7、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】,9.2 插入排序直接插入排序,直接插入排序算法void InsertSort (SqList / 插入到正确位置 /Insertsort,9.2 插入排序直接插入排序,直接插入排序算法分析 时间效率:

8、O(n2)因为在最坏情况下,所有元素的比较次数总和为(01n-1)O(n2)。其他情况下还要加上移动元素的次数。 空间效率:O(1)因为仅占用1个缓冲单元。 算法的稳定性:稳定 直接插入排序算法简洁,容易实现 监视哨、缓冲单元,9.2 插入排序折半插入排序,折半插入排序在已形成的有序表中折半查找,并在适当位置插入,把原来位置上的元素向后顺移。 void BInsertSort (SqList /插入 /for /BInsertSort,9.2 插入排序折半插入排序,折半插入排序算法分析 时间效率:O(n2)比较的次数大大减少,全部元素比较次数仅为O(nlog2n)。虽然比较次数大大减少,可惜移

9、动次数并未减少,所以排序效率仍为O(n2) 。 空间效率:O(1)因为仅占用1个缓冲单元。 算法的稳定性:稳定 折半插入排序不能用于链式结构 折半插入排序的改进2-路插入排序,9.2 插入排序 2-路插入排序,2-路插入排序在折半插入排序的基础上再改进,其目的是减少排序过程中移动记录的次数,但为此需要n个记录的辅助空间。 具体做法是:另设一个和L.r同类型的数组d,首先将L.r1赋值给d1,并将d1看成是在排好序的序列中处于中间位置的记录,然后从L.r中第2个记录起依次插入到d1之前或之后的有序序列中。先将待插记录的关键字和d1的关键字进行比较,若Lri.keyd1.key,则将L.ri插入到

10、d1之前的有序表中。反之,则将L.ri插入到d1之后的有序表中。 实现算法时,可将d看成是一个循环向量,并设两个指针first和final分别指示排序过程中得到的有序序列中的第一个记录和最后一个记录在d中的位置。,9.2 插入排序折半插入排序,2-路插入排序过程,9.2 插入排序 2-路插入排序,在2-路插入排序中,移动记录的次数约为n2/8。因此,2-路插入排序只能减少移动记录的次数,而不能绝对避免移动记录。 当L.r1是待排序记录中关键字最小或最大的记录时,2-路插入排序就完全失去它的优越性。 若希望在排序过程中不移动记录,只有改变存储结构,进行表插入排序。,9.2 插入排序 表插入排序,

11、表插入排序在顺序存储结构中,给每个记录增开一个指针分量,在排序过程中将指针内容逐个修改为已经整理(排序)过的后继记录地址。 优点:在排序过程中不移动元素,只修改指针。 链表排序排序时只移动指针; 地址排序排序时先移动地址,最后再移动记录。 表插入排序具有链表排序和地址排序的特点。,9.2 插入排序 表插入排序,表插入排序过程,9.2 插入排序 表插入排序,表插入排序算法分析: 时间效率:无需移动记录,只需修改2n次指针值。但由于比较次数没有减少,故时间效率仍为O(n2) 。 空间效率肯定低,因为增开了指针分量(但在运算过程中没有用到更多的辅助单元)。 稳定性:稳定。 此算法得到的只是一个有序链

12、表,查找记录时只能满足顺序查找方式。 改进:可以根据表中指针线索,很快对所有记录重排,形成真正的有序表(顺序存储方式),从而能满足折半查找方式。,9.2 插入排序 希尔排序,希尔排序缩小增量排序,先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。 技巧:子序列的构成不是简单地“逐段分割”,而是将相隔某个增量dk的记录组成一个子序列,让增量dk逐趟缩短(例如依次取5,3,1),直到dk1为止。 优点:让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。,9.2 插入排序 希尔排序,

13、具体步骤:假设待排序的记录为n个,先取整数dn,例如,取d=n/2 (n/2 表示不大于n/2的最大整数),将所有距离为d的记录构成一组,从而将整个待排序记录序列分割成为d个子序列,如图8-2所示,对每个分组分别进行直接插入排序,然后再缩小间隔d,例如,取d=d/2,重复上述的分组,再对每个分组分别进行直接插入排序,直到最后取d=1,即将所有记录放在一组进行一次直接插入排序,最终将所有记录重新排列成按关键字有序的序列。,9.2 插入排序 希尔排序,希尔排序执行过程,9.2 插入排序 希尔排序,希尔排序算法 void ShellSort (Sqlist &L,int dlta,int t) /按

14、增量序列dlta0t-1对顺序表L作希尔排序。for(k=0;kt;+t)ShellInsert(L,dltak); /一趟增量为dltak的插入排序 /ShellSort与一趟直接插入排序相比,一趟希尔排序作了以下修改: 前后记录位置的增量是dk,而不是1 r0只是暂存单元,不是哨兵。当j=0时,插入位置已找到。,9.2 插入排序 希尔排序,希尔排序算法void ShellInsert (SqList j-=dk) L.rj+dk=L.rj /记录后移,查找插入位置 L.rj+dk=L.r0; /插入 /if /ShellInsert,9.2 插入排序 希尔排序,希尔排序算法分析 开始时dk

15、 的值较大,子序列中的对象较少,排序速度较快;随着排序进展,dk 值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。 时间效率: O(n1.25)O(1.6n1.25)经验公式 空间效率:O(1)因为仅占用1个缓冲单元 算法的稳定性:不稳定,9.3 交换排序(Exchange Sort ),交换排序两两比较待排序记录的关键码,如果发生逆序(即排列顺序与排序后的次序正好相反),则交换之,直到所有记录都排好序为止。 交换排序的主要算法 冒泡排序 快速排序,9.3 交换排序冒泡排序,冒泡排序每趟不断将记录两两比较,并按“前小后大”(或“前大后小”)

16、规则交换。 优点:每趟结束时,不仅能挤出一个最大值到最后面位置,还能同时部分理顺其他元素;一旦下趟没有交换发生,还可以提前结束排序。 前提:顺序存储结构 例:关键字序列 T=(21,25,49,25*,16,08),9.3 交换排序冒泡排序,冒泡排序过程21,25,49, 25*,16,08 21,25,25*,16, 08 , 4921,25, 16, 08 ,25*,49 21,16, 08 ,25, 25*,49 16,08 ,21, 25, 25*,49 08,16, 21, 25, 25*,49,9.3 交换排序冒泡排序,冒泡排序算法分析 时间效率:O(n2),因为要考虑最坏情况 空

17、间效率:O(1),只在交换时用到一个缓冲单元 稳定性:稳定 详细分析 最好情况:初始排列已经有序,只执行一趟起泡,做 n-1 次关键码比较,不移动对象。 最坏情形:初始排列逆序,算法要执行n-1趟起泡,第i趟(1 i n) 做了n-i次关键码比较,执行了n-i 次对象交换。,9.3 交换排序快速排序(Quick Sort),快速排序是对起泡排序的一种改进,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 优点:因为每趟可以确定不止一个元素的位置,而且呈指数增加,所以特别快! 存储结构:顺序存储结

18、构,9.3 交换排序快速排序(Quick Sort),一趟快速排序(或一次划分):附设两个指针low和high,它们的初值分别为low和high,设枢轴记录的关键字为pivotkey,则首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录和枢轴记录互相交换,然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录和枢轴记录互相交换,重复这两步直至low=high为止。 。,9.3 交换排序快速排序,快速排序过程,9.3 交换排序快速排序,一趟快速排序算法 int Partition(SqList /返回枢轴所在位置 /partition,9.3 交换排序

19、快速排序,改进的一趟快速排序算法 int Partition(SqList /枢轴记录到位 return low; /返回枢轴位置 /Partition,9.3 交换排序快速排序,不断划分子表的过程,计算机如何自动实现? 每一趟的子表的形成是采用从两头向中间交替式逼近法; 由于每趟中对各子表的操作都相似,主程序可采用递归算法。,9.3 交换排序快速排序,快速排序算法(递归形式) void QSort(SqList /对低子表递归排序 QSort(L,pivotloc+1,high);/对高于表递归排序 /QSort void QuickSort(SqList &L) /对顺序表L作快速排序 Q

20、Sort(L,1,L.length); /QuickSort,9.3 交换排序快速排序,快速排序算法分析 时间效率:O(nlog2n),因为每趟确定的元素呈指数增加 空间效率:O(log2n),因为算法的递归性,要用到栈空间 稳定性:不稳定,因为可选任一元素为支点 快速排序算法详细分析 实验结果表明:就平均计算时间而言,快速排序是我们所讨论的所有内排序方法中最好的一个。 最大递归调用层次数与递归树的深度一致,理想情况为 log2(n+1) 。因此,要求存储开销为O(log2n)。 如果每次划分对一个对象定位后,该对象的左侧子序列与右侧子序列的长度相同,则下一步将是对两个长度减半的子序列进行排序

21、,这是最理想的情况。此时,快速排序的趟数最少。,9.3 交换排序快速排序,快速排序算法的退化,08 16 21 25 25* 49,08,0 1 2 3 4 5 pivot,初始,16 21 25 25* 49,08,16,21 25 25* 49,21,08 16,25,25 25* 49,08 16 21,25* 49,25*,08 16 21 25,49,08 16 21 25 25*,i = 1,i = 2,i = 3,i = 4,i = 5,9.3 交换排序快速排序,其排序速度退化到简单排序的水平, 比直接插入排序还慢。占用附加存储(栈)将达到O(n)。 改进办法: 取每个待排序对象

22、序列的第一个对象、最后一个对象和位置接近正中的3个对象,取其排序码居中者作为基准对象。,08 16 21 25 25* 49,0 1 2 3 4 5 pivot,21,初始,08 16,21,25 25* 49,08,25*,08,16,21,25,25*,49,i = 1,i = 2,9.3 交换排序快速排序算法的应用,奇偶数划分问题。 试设计算法在(n)时间内将数组A1n划分为左、右两部分,使得左边所有元素的值均为奇数,右边所有元素的值均为偶数。 荷兰国旗问题。 3种颜色(0,1,2)在一个数组里,每次只可交换一次,扫描一边后,三种颜色自然分开,颜色为:红、白、蓝(荷兰国旗的颜色),所以也

23、叫荷兰国旗问题!,9.4 选择排序(SelectionSort),选择排序每一趟在n-i+1(i=1,2,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。其中最简单的是简单选择排序。 简单选择排序(Simple Selection Sort) 树形选择排序(Tree Selection Sort) 堆排序(Heap Sort),9.4 选择排序简单选择排序,简单选择排序每经过一趟比较就找出一个最小值,与待排序列最前面的位置互换即可。 一趟简单选择排序的操作为:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第(1in)个记录交换之。 显然,对L.r1n中

24、记录进行简单选择排序的算法为:令i从1至n-1,进行n-1趟选择操作。 void SelectSort (SqList i L.rj; /与第i个记录交换 /End of SelectSort,9.4 选择排序简单选择排序,简单选择排序算法分析 时间效率:O(n2)虽移动次数较少,但比较次数仍多。 空间效率:O(1) 算法的稳定性:不稳定 简单选择排序算法 优点:实现简单 缺点:每趟只能确定一个元素,表长为n时需要n-1趟 前提:顺序存储结构,9.4 选择排序简单选择排序,选择排序的主要操作是进行关键字间的比较,因此改进简单选择排序应从如何减少“比较”出发考虑。 能否利用(或记忆)首趟的n-1

25、次比较所得信息,从而尽量减少后续比较次数呢? 实际上,体育比赛中的锦标赛便是一种选择排序。,9.4 选择排序树形选择排序,树形选择(锦标赛)排序与体育比赛时的淘汰赛类似。首先对 n 个记录的关键字进行两两比较,得到 n/2 个优胜者(关键字小者),作为第一步比较的结果保留下来。然后在这 n/2 个较小者之间再进行两两比较,如此重复,直到选出最小关键字的记录为止。 优点:减少比较次数,加快排序速度 缺点:空间效率低 可用一棵有n个叶子结点的完全二叉树表示。,9.4 选择排序树形选择排序,树形选择排序(21,25,49,25*,16,08,63),08,Winner (胜者),21,08,08,6

26、3,25*,21,21,25,49,25*,16,08,63,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree14,初始胜者树,比较次数:6,a0,VS.,VS.,VS.,VS.,VS.,VS.,up,up 对手不参选 VS. 比较,9.4 选择排序树形选择排序,树形选择排序,16,Winner (胜者),21,16,16,63,25*,21,21,25,49,25*,16,63,a1,VS.,VS.,up,输出冠军,调整胜者树,比较次数:,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree1

27、4,9.4 选择排序树形选择排序,树形选择排序,输出亚军,调整胜者树,比较次数:,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree14,21,21,63,63,25*,21,21,25,49,25*,63,a2,VS.,up,Winner (胜者),9.4 选择排序树形选择排序,树形选择排序,输出第三名,调整胜者树,比较次数:,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree14,25,Winner (胜者),25,63,63,25*,25,25,49,25*,63,a3,VS.,VS.,u

28、p,9.4 选择排序树形选择排序,树形选择排序,输出第四名,调整胜者树,比较次数:,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree14,25*,Winner (胜者),25*,63,63,25*,49,25*,63,a4,VS.,up,9.4 选择排序树形选择排序,树形选择排序,输出第五名,调整胜者树,比较次数:,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree14,49,Winner (胜者),49,63,63,49,49,63,a5,VS.,up,up,9.4 选择排序树形选择排序,树

29、形选择排序,输出第六名,结束比赛,比较次数:,tree7 tree8 tree9 tree10 tree11 tree12 tree13 tree14,63,Winner (胜者),63,63,63,a6,up,9.4 选择排序树形选择排序,树形选择排序算法分析 锦标赛排序构成的树是满(完全)二叉树,其深度为 log2n +1,其中 n 为待排序元素个数。 时间效率:O(nlog2n) n个记录各自比较约log2n次 空间效率:O(n)附加内结点共有n(k)-1个! 算法的稳定性:稳定左右结点相同者左为先 在简单选择排序过程中,每当我们从表中选出最小元素之后,再选次最小元素时,必须把表中剩余元

30、素再扫描一次。这样,同一个元素会被扫描多次,浪费! 能否利用上次扫描的结果定出下一次的选择结果呢? 能!堆排序算法,9.4 选择排序堆排序(HeapSort),堆排序只需要一个记录大小的辅助空间,每个待排序的记录仅占有一个存储空间。 什么是堆? 怎样建堆? 怎样堆排序? 根据初始输入数据,利用堆的调整算法建立初始堆。 将当前顶点与堆尾记录交换,然后仿建堆动作重新调整,如此反复直至排序结束。,9.4 选择排序堆排序,堆的定义 n个元素的序列k1,k2,kn当且仅当满足下关系时,称之为堆。 kiK2i且kiK2i+1 (1in/2)小堆 KiK2i且kiK2i+1 (1in/2)大堆 特点 如果让

31、满足以上条件的元素序列(k1,k2,kn)顺次排成一棵完全二叉树,则此树的特点是: 树中所有结点的值均大于(或小于)其左右孩子,此树的根结点(即堆顶)必最大(或最小)。,9.4 选择排序堆排序,有序列T1=(08, 25, 49, 46, 58, 67)和序列T2=(91, 85, 76, 66, 58, 67),判断它们是否 “堆”? 。,08,25,46,49,58,67,0,1,2,3,4,5,08 25 49 46 58 67,初始排序码集合,91,85,66,76,58,67,0,1,2,3,4,5,91 85 76 66 58 67,初始排序码集合,9.4 选择排序堆排序,堆的建立

32、从最后一个非终端结点开始往前逐步调整,让每个双亲大于(或小于)子女,直到根结点为止。,08,25,46,49,58,67,0,1,2,3,4,5,08 25 49 46 58 67,初始排序码集合,i,9.4 选择排序堆排序,建堆算法 void HeapSort (HeapType /将H.R1i-1重新调整为大顶堆 /HeapSort,9.4 选择排序堆排序,一次调整算法 void HeapAdjust(SqList H, int s, int m) /已知H.rsm中记录的关键字除H.rs.key之外均满足堆的定义,本函数调整H.rs的关键字,使H.rsm成为一个大顶堆 rc = H.rs

33、; for (j=2*s; j=m; j*=2) /沿key较大的孩子结点向下筛选,j为key较大的记录的下标 if (jm /插入 /HeapAdjust,9.4 选择排序堆排序,堆排序算法分析 时间效率:O(nlog2n) 整个排序过程中需要调用n-1次HeapAdjust()算法,而算法本身耗时为log2n; 空间效率:O(1)仅在第二个for循环中交换记录时用到一个临时变量。 稳定性:不稳定。 优点:对小文件效果不明显,但对大文件有效。 堆排序在最坏的情况下,其时间复杂度也为O(nlog2n)。相对于快速排序来说,这是堆排序的最大优点。,9.5 归并排序(Merge Sort),归并排

34、序将两个(或以上)的有序表组成新的有序表。 可以把一个长度为n 的无序序列看成是 n 个长度为 1 的有序子序列 ,首先做两两归并,得到 n / 2 个长度为 2 的子序列 ;再做两两归并,如此重复,直到最后得到一个长度为 n 的有序序列。,9.5 归并排序,归并排序过程,21,25,25*,25*,93,62,72,08,37,16,54,49,21,25,49,62,93,08,72,16,37,54,21,25,25*,49,08,62,72,93,16,37,54,08,08,21,16,25,21,25*,25,49,25*,62,37,72,49,93,54,16,37,54,62

35、,72,93,len=1,len=2,len=4,len=8,len=16,归并排序过程递推,9.5 归并排序,2-路归并排序中的核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列。非递归算法 void Merge(RcdType SR ,RcdType / 将剩余的SRjn复制到TR /merge,9.5 归并排序,归并排序过程递归,21 25 49 25* 16 08,21 25 49,25* 16 08,21,25,49,25 49,21,25*,16 08,25*,16,08,21 25 49 25* 16 08,16 08,25*,25 49,21,递 归,21,25*,

36、16,08,49,25,25* 16 08,21 25 49,回推,9.5 归并排序,递归算法 void Merge(ElemType *r,ElemType *rf,int u,int v,int t)for (i=u,j=v,k=u;iv & j=t;k+) if (ri.keyrj.key) rfk=ri;i+;else rfk=rj;j+;if (iv) rfkt=riv-1;if(j=t) rfkt=rjt;,9.5 归并排序,递归算法 void MSort(ElemType *p,ElemType *p1,int s,int t) if (s=t) p1s=pselse m=(s+

37、t)/2; /*平分*p表*/MSort(p,p2,s,m);/*递归地将psm归并为有序的表*/MSort(p,p2,m+1,t);/*递归地将pm+1t归并为有序表*/Merge(p2,p1,s,m+1,t);/*将p2sm和p2m+1t归并到p1st*/void MergeSort(S_TBL *p) /*对顺序表*p作归并排序*/MSort(p-elem,p-elem,1,p-length);,9.5 归并排序,归并排序算法分析 时间效率:O(nlog2n) 在递归的归并排序算法中,函数Merge()做一趟两路归并排序,需要调用merge()函数 n/(2*len) O(n/len)

38、次,函数Merge()调用Merge( )正好log2n 次,而每次merge()要执行比较O(len)次,所以算法总的时间复杂度为O(nlog2n)。 空间效率:O(n) 需要一个与原始序列同样大小的辅助序列(TR)。这正是此算法的缺点。 稳定性:稳定。,9.6 基数排序(Radix Sort ),基数排序借助多关键字排序的思想对单逻辑关键字进行排序。即:用关键字不同的位值进行排序。 和前面所述各类排序方法完全不相同的一种排序方法。从前几节的讨论可见,实现排序主要是通过关键字间的比较和移动记录这两种操作,而实现基数排序不需要进行记录关键字间的比较。 什么是“多关键字”排序?实现方法? 单逻辑

39、关键字怎样“按位值”排序?,9.6 基数排序(Radix Sort ),什么是“多关键字”排序?如何实现? 例:对一副扑克牌该如何排序? 若规定花色和面值的顺序关系为: 花色: 面值:2 3 4 5 6 7 8 9 10 J Q K A 则可以先按花色排序,花色相同者再按面值排序; 也可以先按面值排序,面值相同者再按花色排序。 例:职工分房该如何排序? 单位规定:先以总分排序(职称分学历分); 总分相同者,再工龄分排序,其次按配偶职称、配偶工龄、人口等等排序。,9.6 基数排序(Radix Sort ),实现方法 最高位优先法MSD(Most Significant Digit first)

40、最低位优先法LSD(Least Significant Digit first) 对一副扑克牌该如何排序? 若规定花色为第一关键字(高位),面值为第二关键字(低位),则使用MSD和LSD方法都可以达到排序目的。 MSD方法的思路:先设立4个花色“箱”,将全部牌按花色分别归入4个箱内(每个箱中有13张牌);然后对每个箱中的牌按面值进行插入排序(或其它稳定算法)。 LSD方法的思路:先按面值分成13堆(每堆4张牌),然后对每堆中的牌按花色进行排序(用插入排序等稳定的算法)。,9.6 基数排序(Radix Sort ),单逻辑关键字怎样“按位值”排序? 设n 个记录的序列为:V0, V1, , Vn

41、-1 ,可以把每个记录Vi的单关键码 Ki看成是一个d元组(Ki1, Ki2, , Kid),则其中的每一个分量Kij( 1 j d ) 也可看成是一个关键字。 Ki1最高位,Kid最低位;Ki共有d位,可看成d元组; 每个分量Kij (1 j d ) 有radix种取值,则称radix为基数。 关键码984可以看成是3元组;基数radix为10。 关键码dian可以看成是4元组;基数radix为26。,9.6 基数排序(Radix Sort ),初始关键字序列T=(32,13,27,32*,19,33),请分别用MSD和LSD进行排序,并讨论其优缺点。 MSD:原始序列: 32,13,27,

42、32*,19,33 先按高位Ki1排序:(13,19),27,(32,32*,33)再按低位Ki2 排序 :13,19, 27,32,32*,33 因为有分组,故此算法需递归实现。 LSD: 原始序列: 32,13,27,32*,19,33 先按低位Ki2排序: 32,32*,13,33,27,19 再按高位Ki1排序: 13,19,27,32,32*,33 无需分组,易编程实现! 通过若干次“分配”和“收集”来实现排序链式基数排序。,9.6 基数排序链式基数排序,614,921,485,637,738,101,215,530,790,306,第一趟分配(按最低位 i = 3 ),re0 re

43、1 re2 re3 re4 re5 re6 re7 re8 re9,614,738,921,485,637,101,215,530,790,306,fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9,第一趟收集,530,790,921,101,614,485,215,306,637,738,9.6 基数排序链式基数排序,614,921,485,637,738,101,215,530,790,306,第二趟分配(按次低位 i = 2 ),re0 re1 re2 re3 re4 re5 re6 re7 re8 re9,614,738,921,485,637,101,21

44、5,530,790,306,fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9,第二趟收集,530,790,921,101,614,485,215,306,637,738,9.6 基数排序链式基数排序,614,921,485,637,738,101,215,530,790,306,第三趟分配(按最高位 i = 1 ),re0 re1 re2 re3 re4 re5 re6 re7 re8 re9,614,738,921,485,637,101,215,530,790,306,fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9,第三趟收集,

45、530,790,921,101,614,485,215,306,637,738,9.6 基数排序链式基数排序,链式基数排序算法 #define MAX_NUM_OF_KEY 8 /关键字项数的最大值 #define RADIX 10 /关键字基数,此时是十进制整数的基数 #define MAX_SPACE 10000 typedef struct keysType keysMAX_NUM_OF_KEY; /关键字 InfoType otheritems; /其它数据项 int next; SLCell; /静态链表的结点类型 typedef struct SLCell rMAX_SPACE; /静态链表的可利用空间,r0为头结点 int keynum; /记录的当前关键字个数 int recnum; /静态链表的当前长度 SLList; /静态链表类型 typedef int ArrType RADIX; /指针数组类型,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 实用文档 > 往来文书

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报