《数据结构第10章内部排序》由会员分享,可在线阅读,更多相关《数据结构第10章内部排序(107页珍藏版)》请在金锄头文库上搜索。
1、数据结构课程的内容数据结构课程的内容110.1 10.1 概述概述10.210.2 插入排序插入排序10.3 10.3 交换排序交换排序10.4 10.4 选择排序选择排序10.5 10.5 归并排序归并排序10.6 10.6 基数排序基数排序第第1010章章 内部排序内部排序210.1 10.1 概述概述1. 什么是排序?什么是排序? 将一组杂乱无章的将一组杂乱无章的数据数据按一定的按一定的规律规律顺次排列起来。顺次排列起来。 2. 排序的目的是什么?排序的目的是什么?存放在数据表中存放在数据表中按按关键字排序关键字排序3.3.排序算法的好坏如何衡量?排序算法的好坏如何衡量?时间效率时间效率
2、排序速度排序速度( (即排序所花费的全部比较次数即排序所花费的全部比较次数) )空间效率空间效率占内存辅助空间的大小占内存辅助空间的大小稳稳定定性性若若两两个个记记录录A A和和B B的的关关键键字字值值相相等等,但但排排序序后后A A、B B的的先先后后次次序序保保持持不不变变,则则称称这这种种排排序序算算法法是是稳稳定定的。的。 便于查找!便于查找!34. 什么叫内部排序?什么叫外部排序什么叫内部排序?什么叫外部排序? 若待排序记录都在内存中,称为内部排序;若待排序记录都在内存中,称为内部排序;若待排序记录一部分在内存,一部分在外存,则若待排序记录一部分在内存,一部分在外存,则称为外部排序
3、。称为外部排序。注:注:外部排序时,要将数据分批调入内存来排序,中间外部排序时,要将数据分批调入内存来排序,中间结果还要及时放入外存,显然外部排序要复杂得多。结果还要及时放入外存,显然外部排序要复杂得多。 5.5.待排序记录在内存中怎样存储和处理?待排序记录在内存中怎样存储和处理? 顺序顺序排序排序排序时直接移动记录;排序时直接移动记录; 链表链表排序排序排序时只移动指针;排序时只移动指针; 地址地址排序排序排序时先移动地址,最后再移动记录。排序时先移动地址,最后再移动记录。注:注:地址排序地址排序中可以增设一维数组来专门存放记中可以增设一维数组来专门存放记录的地址。录的地址。4注:注:大多数
4、排序算法都是针对顺序表结构的大多数排序算法都是针对顺序表结构的( (便于直接移动元素便于直接移动元素) )6. 6. 顺序存储(顺序表)的抽象数据类型如何表示?顺序存储(顺序表)的抽象数据类型如何表示?Typedef struct /定义每个记录(数据元素)的结构定义每个记录(数据元素)的结构 KeyType key ; /关键字关键字 InfoType otherinfo; /其它数据项其它数据项RecordType ;# define MAXSIZE 20 /设记录不超过设记录不超过2020个个typedef int KeyType ; /设关键字为整型量(设关键字为整型量(intint型
5、)型)Typedef struct /定义顺序表的结构定义顺序表的结构 RecordType r MAXSIZE +1 ; /存储顺序表的向量,存储顺序表的向量,r0r0 一般作哨兵或缓冲区一般作哨兵或缓冲区 int length ; /顺序表的长度顺序表的长度SqList ;57. 内部排序的算法有哪些?内部排序的算法有哪些?按排序的规则不同,可分为按排序的规则不同,可分为5类:类:插入排序插入排序交换排序(重点是快速排序)交换排序(重点是快速排序)选择排序选择排序归并排序归并排序基数排序基数排序d关键字的位数关键字的位数(长度长度)按排序算法的时间复杂度不同,可分为按排序算法的时间复杂度不
6、同,可分为3类:类:简单的排序算法:时间效率低,简单的排序算法:时间效率低,O(n2)先进的排序算法先进的排序算法: 时间效率高,时间效率高,O( nlog2n )基数排序算算法:时间效率高,基数排序算算法:时间效率高,O( dn)610.210.2 插入排序插入排序插入排序的基本思想是:插入排序的基本思想是: 每步将一个待排序的对象,按每步将一个待排序的对象,按其关键字大小,其关键字大小,插入到前面插入到前面已经排好序的一组对象已经排好序的一组对象的的适适当位置当位置上上,直到对象全部插入为止。,直到对象全部插入为止。插入排序的基本操作:插入排序的基本操作: 将记录将记录Ri插入到有序子序列
7、插入到有序子序列R1.i-1中,使中,使记录的有序序列从记录的有序序列从R1.i-1变为变为R1.i。显然,完成这个显然,完成这个“插入插入”需分三步进行:需分三步进行:1查找查找Ri的插入位置的插入位置j+1;2将将Rj+1.i-1中的记录后移一个位置;中的记录后移一个位置;3将将Ri复制到复制到Rj+1的位置上。的位置上。710.210.2 插入排序插入排序插入排序有多种具体实现算法:插入排序有多种具体实现算法: 1) 直接插入排序直接插入排序 2) 折半插入排序折半插入排序 3) 表插入排序表插入排序 4) 希尔排序希尔排序 简言之,边插入边排序,保证子序列中简言之,边插入边排序,保证子
8、序列中随时都是排好序的。随时都是排好序的。81) 直接插入排序直接插入排序新元素插入到哪里?新元素插入到哪里?例例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
9、, 6, 9, 13,27, 31】, 11【3, 5, 6, 9, 11,13,27, 31】 在已形成的在已形成的有序表中有序表中线性查找线性查找,并在适当位置插入,并在适当位置插入,把原来位置上的元素向后把原来位置上的元素向后顺移顺移。最简单的排序法!最简单的排序法!最简单的排序法!最简单的排序法!9例例2 2:关键字序列关键字序列T= (21,25,49,25*,16,08),),请写出直接插入排序的具体实现过程。请写出直接插入排序的具体实现过程。* *表示后一个表示后一个2525i i=1=121212525494925*25*161608080 1 2 3 4 5 6暂暂存存212
10、1i i=2=2i i=3=3i i=5=5i i=4=4i i=6=62525252525494949494925*25*25*494916161625*25*0808084949解:解:假设该序列已存入一维数组假设该序列已存入一维数组V7V7中,将中,将V0V0作为作为缓冲或暂存单元(缓冲或暂存单元(TempTemp)。)。则程序执行过程为:则程序执行过程为:21212525494925*25*2121初态:初态:1616494925*25*2525212116160808完成!时间效率:时间效率: O(nO(nO(nO(n2 2 2 2) ) ) )因为在最坏情况下,所有元素的比因为在最
11、坏情况下,所有元素的比较次数总和为(较次数总和为(0 01 1n-1)O(nn-1)O(n2 2) )。其他情其他情况下还要加上移动元素的次数。况下还要加上移动元素的次数。 空间效率:空间效率:O O O O(1 1 1 1)因为仅占用因为仅占用1 1个缓冲单元个缓冲单元算法的稳定性:算法的稳定性:稳定稳定稳定稳定因为因为25*25*排序后仍然在排序后仍然在2525的后面。的后面。 10直接插入排序算法的三个要点:直接插入排序算法的三个要点:1从从Ri-1起向前顺序查找,监视哨设置在起向前顺序查找,监视哨设置在R0R0 = Ri; / 设置设置“哨兵哨兵”for (j=i-1; R0.keyR
12、j.key; -j) ; / 从后往前找从后往前找return j+1; / 返回返回Ri的插入位置为的插入位置为j+12对于在查找过程中找到的关键字不小于对于在查找过程中找到的关键字不小于Ri.key的记录,在查找的同时实现记录向后移动;的记录,在查找的同时实现记录向后移动;for (j=i-1; R0.keyRj.key; -j) Rj+1 = Rj3i = 2,3,, n, 实现整个序列的排序。实现整个序列的排序。11直接插入排序算法描述如下直接插入排序算法描述如下:void InserSort ( SqList &L) / 对顺序表对顺序表L作直接插入排序。作直接插入排序。 for (
13、 i=2; i=L.length; +i )if (LT(L.ri.key ,L.ri-1.key) L.r0 = L.ri; / 复制为监视哨复制为监视哨 for ( j=i-1; LT(L.ri.key ,L.ri-1.key) ; -j ) L.rj+1 = L.rj; / 记录后移记录后移 L.rj+1 = L.r0;/ 插入到正确位插入到正确位置置 / InsertSort12n若设待排序的对象个数为若设待排序的对象个数为n,则算法需要进行则算法需要进行n-1次插入。次插入。n最好情况下,排序前对象已经按关键字大小从最好情况下,排序前对象已经按关键字大小从小到大有序,每趟只需与前面的
14、有序对象序列小到大有序,每趟只需与前面的有序对象序列的的最后一个对象最后一个对象的关键字比较的关键字比较 1 1 次。因此,次。因此,总的关键字比较次数为总的关键字比较次数为n-1。直接插入排序的算法分析直接插入排序的算法分析13最坏情况下,第最坏情况下,第i趟插入时,第趟插入时,第i个对象必须与个对象必须与前面前面i-1个对象都做关键字比较,并且每做个对象都做关键字比较,并且每做 1 1 次比较就要做次比较就要做 1 1 次数据移动。则总的关键字次数据移动。则总的关键字比较次数比较次数KCN和对象移动次数和对象移动次数RMN分别为分别为14若待排序对象序列中出现各种可能排列的概率相同,若待排
15、序对象序列中出现各种可能排列的概率相同,则可取上述最好情况和最坏情况的平均情况。在平均则可取上述最好情况和最坏情况的平均情况。在平均情况下的关键字比较次数和对象移动次数约为情况下的关键字比较次数和对象移动次数约为 n2/4。因此,直接插入排序的时间复杂度为因此,直接插入排序的时间复杂度为 o(n2)。直接插入排序是一种稳定的排序方法。直接插入排序是一种稳定的排序方法。152) 折半插入排序折半插入排序优优点点:比比较较的的次次数数大大大大减减少少,全全部部元元素素比比较较次次数数仅仅为为O(nlogO(nlog2 2n)n)。时时间间效效率率:虽虽然然比比较较次次数数大大大大减减少少,可可惜惜
16、移移动动次次数数并并未减少,所以排序效率仍为未减少,所以排序效率仍为O(nO(n2 2) ) 。空间效率:空间效率: O O(1 1)稳定性:稳定性:稳定稳定 当待排序记录的数量当待排序记录的数量n很小时,直接插入排序是一种很小时,直接插入排序是一种简便的方法;但当记录数量简便的方法;但当记录数量n很大时,则不宜采用直接插很大时,则不宜采用直接插入排序。入排序。 由于插入排序的基本操作是在有序表由于插入排序的基本操作是在有序表R1.i-1中进行中进行查找和插入的;则可以利用查找和插入的;则可以利用折半查找实现折半查找实现“在在R1.i-1中中查找查找Ri的插入位置的插入位置”,并在适当位置插入
17、,把原来位置并在适当位置插入,把原来位置上的元素向后上的元素向后顺移顺移。如此实现的插入排序为如此实现的插入排序为折半插入排折半插入排折半插入排折半插入排序序序序。16折半插入排序算法描述如下折半插入排序算法描述如下:void BInserSort ( SqList &L) / 对顺序表对顺序表L作折半插入排序。作折半插入排序。 for ( i=2; i=L.length; +i ) L.r0 = L.ri; while(low=high+1; - -j ) L.rj+1 = L.rj; / 记录后移记录后移 L.rj+1 = L.r0;/ 插入插入 /for / BInsertSort17讨
18、论:讨论:若记录是链表结构,用直接插入排序若记录是链表结构,用直接插入排序行否?折半插入排序呢?行否?折半插入排序呢?答:答:直接插入不仅可行,而且还无需移动元直接插入不仅可行,而且还无需移动元素,时间效率更高!素,时间效率更高!折半插入排序的改进折半插入排序的改进2-路插入排序见教材路插入排序见教材P267。但链表无法但链表无法“折半折半”!18折半插入排序的算法分析折半插入排序的算法分析折半查找比顺序查找快,所以折半插入排序折半查找比顺序查找快,所以折半插入排序就平均性能来说比直接插入排序要快。就平均性能来说比直接插入排序要快。在插入第在插入第 i 个对象时,需要经过个对象时,需要经过 l
19、og2i +1 次关键字比较,才能确定它应插入的位置。次关键字比较,才能确定它应插入的位置。因此,将因此,将 n 个对象用折半插入排序所进行的个对象用折半插入排序所进行的关键字比较次数为:关键字比较次数为:n*log2n折半插入排序是一个稳定的排序方法。折半插入排序是一个稳定的排序方法。193)表插入排序)表插入排序基本思想基本思想:在顺序存储结构中,给每个记录增开一:在顺序存储结构中,给每个记录增开一个指针分量,在排序过程中将指针内容逐个修改为个指针分量,在排序过程中将指针内容逐个修改为已经整理(排序)过的后继记录地址。已经整理(排序)过的后继记录地址。优点:优点:在排序过程中不移动元素,只
20、修改指针。在排序过程中不移动元素,只修改指针。回忆:回忆: 链表排序链表排序排序时只移动指针;排序时只移动指针; 地址排序地址排序排序时先移动地址,最后再移排序时先移动地址,最后再移动记录。动记录。此方法具有链表排序和地址排序的特点。此方法具有链表排序和地址排序的特点。201例:例:关键字序列关键字序列 T=(21,25,49,25*,16,08), 请请写出表插入排序的具体实现过程。写出表插入排序的具体实现过程。解:解:假设该序列(结构类型假设该序列(结构类型) )已存入有序链表已存入有序链表SL7SL7 中,中,将将SL0SL0 作为表头结点作为表头结点。则则算法执行过程算法执行过程为:为
21、:i 关键字关键字 SLi.key指针指针 SLi.next0 MaxInt1212253494 25*516608指向第指向第1 1个元素个元素指向头结点指向头结点初态初态初态初态i=1i=1i=1i=1i=2i=2i=2i=2i=3i=3i=3i=3i=4i=4i=4i=4i=5i=5i=5i=5i=6i=6i=6i=6034 45 5 6 65 503 31 102* *表示后一个表示后一个2525静态链表静态链表21表插入排序算法分析:表插入排序算法分析: 无需移动记录,只需修改无需移动记录,只需修改2n次指针值。但由于比次指针值。但由于比较次数没有减少,故较次数没有减少,故时间效率仍
22、为时间效率仍为O(n2) 。 空间效率肯定低空间效率肯定低,因为增开了指针分量(但在运,因为增开了指针分量(但在运算过程中没有用到更多的辅助单元)。算过程中没有用到更多的辅助单元)。 稳定性:稳定性:25和和25*排序前后次序未变,排序前后次序未变,稳定稳定。讨论:讨论:此算法得到的只是一个有序链表,查找记录此算法得到的只是一个有序链表,查找记录时只能满足顺序查找方式。时只能满足顺序查找方式。改进:改进:可以根据表中指针线索,很快对所有记录重可以根据表中指针线索,很快对所有记录重排,形成排,形成真正的有序表(顺序存储方式),从而真正的有序表(顺序存储方式),从而能满足折半查找方式。能满足折半查
23、找方式。具体实现见教材具体实现见教材P269。224)希尔()希尔(shell)排序排序(又称缩小增量排序(又称缩小增量排序)基本思想基本思想:先将整个待排记录序列分割成若干子序列先将整个待排记录序列分割成若干子序列, ,分分别进行直接插入排序,待整个序列中的记录别进行直接插入排序,待整个序列中的记录“基本有序基本有序”时,再对全体记录进行一次直接插入排序。时,再对全体记录进行一次直接插入排序。技巧:技巧:子序列的构成不是简单地子序列的构成不是简单地“逐段分割逐段分割”,而是将相,而是将相隔某个增量隔某个增量dkdk的的记录组成一个子序列记录组成一个子序列, ,让增量让增量dkdk逐趟逐趟缩短
24、缩短(例如依次取(例如依次取5,3,15,3,1),直到),直到dkdk1 1为止。为止。优点:优点:让关键字值小的元素能很快前移,且序列若基本有让关键字值小的元素能很快前移,且序列若基本有序时,再用直接插入排序处理,时间效率会高很多。序时,再用直接插入排序处理,时间效率会高很多。2338例:例:关键字序列关键字序列 T=(49,38,65,97, 76, 13, 27, 49*,55, 04),),请写出希尔排序的具体实现过程。请写出希尔排序的具体实现过程。0123456789104938659776132749*5504初态:初态:第第1趟趟 (dk=5)第第2趟趟 (dk=3)第第3趟趟
25、 (dk=1)4913134938276549*975576042738 65 49*9755135576045513270427044949*4949*763876 65 65 9797551327044949*3876 65 9713 27 0449* 76 97 算法分析:算法分析:开始时开始时dk 的值较大,子序列中的对象较少,的值较大,子序列中的对象较少,排序速度较快;随着排序进展,排序速度较快;随着排序进展,dk 值逐渐变小,子序值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。对象
26、已基本有序,所以排序速度仍然很快。riri问题问题:第三趟:第三趟(dk=1)(dk=1)的排序过程与在初态序列上直接进的排序过程与在初态序列上直接进行行dk=1dk=1排序是否相同?排序是否相同?24void ShellSort(SqList &L,int dlta ,int t) /按增量序列按增量序列dlta0t-1对顺序表对顺序表L作作Shell排排序序 for(k=0;kt;+k) ShellInsert(L,dltak); /增量为增量为dltak的一趟的一趟插入排序插入排序 / ShellSort时间效率:时间效率:空间效率:空间效率:O O O O(1 1 1 1)因为仅占用因
27、为仅占用1 1个缓冲单元个缓冲单元算法的稳定性:算法的稳定性:不稳定不稳定不稳定不稳定因为因为4949* *排序后却到了排序后却到了4949的前面的前面希尔排序算法希尔排序算法希尔排序算法希尔排序算法(主程序)(主程序)(主程序)(主程序)参见教材参见教材P272P272O(O(O(O(n n1.31.3)经验公式经验公式dkdk值依次装在值依次装在dltadlta t t 中中25void ShellInsert(SqList &L,int dk) for(i=dk+1;i=L.length; + i) if(L.ri.key 0&(L.r0.keyL.rj.key); j=j-dk)L.
28、rj+dk=L.rj; L.rj+dk=L.r0; 希尔排序算法希尔排序算法希尔排序算法希尔排序算法(其中某一趟的排序操作)(其中某一趟的排序操作)(其中某一趟的排序操作)(其中某一趟的排序操作)参见教材参见教材P272P272/对顺序表对顺序表L进行一趟增量为进行一趟增量为dk的的Shell排序,排序,dk为步长因子为步长因子/开始将开始将ri 插入有序增量子表插入有序增量子表/暂存在暂存在r0/关键字较大的记录在子表中后移关键字较大的记录在子表中后移/在本趟结束时将在本趟结束时将ri插入到正确位置插入到正确位置26课堂练习:课堂练习:1. 欲将序列(欲将序列(Q, H, C, Y, P,
29、A, M, S, R, D, F, X)中的关键字按中的关键字按字母升序重排,则初始步长为字母升序重排,则初始步长为4的希尔排序一趟的结果是?的希尔排序一趟的结果是?答:答:原始序列:原始序列: Q, H, C, Y, P, A, M, S, R, D, F, X shellshell一趟后:一趟后:P,Q,R,A,D,H,C,F,M,S,X ,Y272. 以以关关键键字字序序列列(256,301,751,129,937,863,742,694,076,438)为为例例,分分别别写写出出执执行行以以下下算算法法的的各各趟趟排排序序结结束束时时,关关键键字字序序列列的的状状态态,并并说说明明这这
30、些些排排序序方方法法中中,哪哪些些易易于于在在链链表表(包包括括各各种种单单、双双、循循环环链链表表)上实现?上实现? 直接插入排序直接插入排序 希尔排序(取希尔排序(取dk=5,3,1)答:答:显然,直接插入排序方法易于在链表上实现;显然,直接插入排序方法易于在链表上实现;但希尔排序方法因为是按增量选择记录,不易于在但希尔排序方法因为是按增量选择记录,不易于在链表上实现。链表上实现。 两种排序方法的中间状态分别描述如后:两种排序方法的中间状态分别描述如后:28原始序列:原始序列: 256256,301301,751751,129129,937937,863863,742742,694694,
31、076076,438438 256256,301301 ,751751,129129,937937,863863,742742,694694,076076,438438 256256,301301,751751 ,129129,937937,863863,742742,694694,076076,438438 129129,256256,301301,751751 ,937937,863863,742742,694694,076076,438438 129129,256256,301301,751751,937937 ,863863,742742,694694,076076,438438 12
32、9129,256256,301301,751751,863863,937937 ,742742,694694,076076,438438 129129,256256,301301,742742,751751,863863,937937 ,694694,076076,438438 129129,256256,301301,694694,742742,751751,863863,937937 ,076076,438438 076076,129129,256256,301301,694694,742742,751751,863863,937937 ,438438 076076,129129,2562
33、56,301301,438438,694694,742742,751751,863863,937937 第第1趟趟第第2趟趟第第3趟趟第第4趟趟第第5趟趟第第6趟趟第第7趟趟第第8趟趟第第9趟趟29原始序列:原始序列: 256256,301301,751751,129129,937937,863863,742742,694694,076076,438438( (取取取取dkdk=5,3,1)=5,3,1)256256,301301,751751,129129,937937,863863,742742,694694,076076,438438256256,301301,751751,129129
34、,937937,863863,742742,694694,076076,438438256256,301301,694694,129129,937937,863863,742742,751751,076076,438438256256,301301,694694,076076,937937,863863,742742,751751,129129,438438256256,301301,694694,076076,438438,863863,742742,751751,129129,937937第第1趟趟dkdk=5=5第第2趟趟dkdk=3=3第第3趟趟dkdk=1=1256256,30130
35、1,694694,076076,438438,863863,742742,751751,129129,937937256256,301301,694694,076076,438438,863863,742742,751751,129129,937937076076,301301,694694,256256,438438,863863,742742,751751,129129,937937076076,301301,694694,256256,438438,863863,742742,751751,129129,937937076076,301301,694694,256256,438438,8
36、63863,742742,751751,129129,937937076076,301301,129129,256256,438438,694694,742742,751751,863863,937937076076,301301,129129,256256,438438,694694,742742,751751,863863,937937076076,301301,129129,256256,438438,694694,742742,751751,863863,937937076076,129129,256256,301301,438438,694694,742742,751751,8638
37、63,9379373010.3 10.3 快速排序快速排序 两两比较待排序记录的关键两两比较待排序记录的关键字,如果发生逆序(即排列顺序与排序后的次序正好字,如果发生逆序(即排列顺序与排序后的次序正好相反),则交换之,直到所有记录都排好序为止。相反),则交换之,直到所有记录都排好序为止。快速排序的主要算法有:快速排序的主要算法有: 1) 冒泡排序冒泡排序 2) 快速排序快速排序快速排序的基本思想是:快速排序的基本思想是:31 1) 冒泡排序冒泡排序冒泡排序冒泡排序基本思路:基本思路:每趟不断将记录两两比较,并按每趟不断将记录两两比较,并按“前小前小后大后大”(或(或“前大后小前大后小”)规则交
38、换。)规则交换。优点:优点:每趟结束时,不仅能挤出一个最大值到最后每趟结束时,不仅能挤出一个最大值到最后面位置,还能同时部分理顺其他元素;一旦面位置,还能同时部分理顺其他元素;一旦下趟没有交换发生,还可以提前结束排序。下趟没有交换发生,还可以提前结束排序。前提:前提:顺序存储结构顺序存储结构 例:例:关键字序列关键字序列 T=(21,25,49,25*,16,08),),请请写出冒泡排序的具体实现过程。写出冒泡排序的具体实现过程。(假设假设“前小后大前小后大”)21,25,49, 25*,16, 0821,25,25*,16, 08 , 4921,25, 16, 08 ,25*,4921,16
39、, 08 ,25, 25*,4916,08 ,21, 25, 25*,4908,16, 21, 25, 25*,49初态:初态:第第1趟趟第第2趟趟第第3趟趟第第4趟趟第第5趟趟32冒泡排序的算法分析冒泡排序的算法分析时间效率:时间效率:O O(n n2 2) ) 因为要考虑最坏情况因为要考虑最坏情况空间效率:空间效率:O O(1 1) 只在交换时用到一个缓冲单元只在交换时用到一个缓冲单元稳稳 定定 性:性: 稳定稳定 2525和和2525* *在排序前后的次序未改变在排序前后的次序未改变详细分析:详细分析:最好情况:最好情况:初始排列已经有序,只执行一趟起泡,做初始排列已经有序,只执行一趟起
40、泡,做 n- -1 次关键字比较,不移动对象。次关键字比较,不移动对象。最坏情形:最坏情形:初始排列逆序,初始排列逆序,算法要执行算法要执行n-1 1趟起泡,第趟起泡,第i趟趟(1 i n) 做了做了n- i 次关键字比较,执行了次关键字比较,执行了n-i 次对象次对象交换。此时的比较总次数交换。此时的比较总次数KCN和记录移动次数和记录移动次数RMN为:为:332 2) 快速排序快速排序快速排序快速排序 从待排序列中任取一个元素从待排序列中任取一个元素 ( (例如取第一个例如取第一个) ) 作为中心,所有比它小的元素一律前放,所有比它作为中心,所有比它小的元素一律前放,所有比它大的元素一律后
41、放,形成左右两个子表;然后再对大的元素一律后放,形成左右两个子表;然后再对各子表重新选择中心元素并依此规则调整,直到每各子表重新选择中心元素并依此规则调整,直到每个子表的元素只剩一个。此时便为有序序列了。个子表的元素只剩一个。此时便为有序序列了。基本思想:基本思想:基本思想:基本思想:优点:优点:因为每趟可以确定不止一个元素的位置,而且因为每趟可以确定不止一个元素的位置,而且呈指数增加,所以特别快!呈指数增加,所以特别快! 前提:前提:顺序存储结构顺序存储结构 34( ),设以首元素为枢轴中心设以首元素为枢轴中心例例1:关键字序列关键字序列 T=(21,25,49,25*,16,08),),请
42、写出快速排序的算法步请写出快速排序的算法步骤。骤。21, 25, 49, 25*,16, 08初态:初态:第第1趟:趟:第第2趟:趟:第第3趟:趟:讨论:讨论:讨论:讨论:1. 1. 1. 1. 这种不断划分子表的过程,计算机如何自动实现?这种不断划分子表的过程,计算机如何自动实现?这种不断划分子表的过程,计算机如何自动实现?这种不断划分子表的过程,计算机如何自动实现?2. “2. “2. “2. “快速排序快速排序快速排序快速排序”是否真的比任何排序算法都快?是否真的比任何排序算法都快?是否真的比任何排序算法都快?是否真的比任何排序算法都快?08,16,21,25, 25*,(49)2116
43、,08,( )25,25*,49(08),16,21,25,(25*,49)351.1.1.1.这种不断划分子表的过程,计算机如何自动实现?这种不断划分子表的过程,计算机如何自动实现?这种不断划分子表的过程,计算机如何自动实现?这种不断划分子表的过程,计算机如何自动实现?编程时:编程时:每一趟的子表的形成是采用从两头向中间交替式逼近法每一趟的子表的形成是采用从两头向中间交替式逼近法; ;由于每趟中对各子表的操作都相似,主程序可采用递归由于每趟中对各子表的操作都相似,主程序可采用递归算法。算法。见教材见教材P275intint PartitionPartitionPartitionPartiti
44、on( (SqListSqList &L, &L,intint low low, ,intint high high) ) /交换顺序表交换顺序表 L.rlowhighL.rlowhigh 的记录,使枢轴记录到位,的记录,使枢轴记录到位,并返回其位置。返回时,在枢轴之前的记录均不大于它,并返回其位置。返回时,在枢轴之前的记录均不大于它,枢轴之后的记录均不小于它。枢轴之后的记录均不小于它。 pivotkey=L.pivotkey=L.rlow.keyrlow.key; ; /取枢轴的关键字存入取枢轴的关键字存入pivotkeypivotkey变量变量(续下页)(续下页)一趟快速排序算法一趟快速排
45、序算法(针对一个子表的操作)(针对一个子表的操作)36while(low high) /从表的两端交替地向中间扫描从表的两端交替地向中间扫描 while(low=pivotkey ) - -high; L.rlowL.rhigh; /将比枢轴小的记录交换到低将比枢轴小的记录交换到低端端 while(lowhigh & L.rlow.key=pivotkey) + +low;L.rhigh L.rlow;/将比枢轴大的记录交换到将比枢轴大的记录交换到高端高端 return low; /返回枢轴记录所在位置。返回枢轴记录所在位置。/Partition37Low=high=Low=high=Low=
46、high=Low=high=3 3 3 3,本趟停止,将本趟停止,将本趟停止,将本趟停止,将支点定位并返回位置信息支点定位并返回位置信息支点定位并返回位置信息支点定位并返回位置信息例例2:关键字序列关键字序列 T=(21,25,49,25*,16,08),),请写出快速排序算法的一趟实现过程。请写出快速排序算法的一趟实现过程。ri0123456初态初态21254925*1608第第1趟趟highhighlowlow210825164925*321pivotkeypivotkey= =212108251649( 08 ,16 ) 21 ( 25* , 49, 25 )25252525* * *
47、*跑到了前面,跑到了前面,跑到了前面,跑到了前面,不稳定不稳定不稳定不稳定!38j从高端从高端扫描扫描寻找小于寻找小于pivot的的元素元素i从低端从低端扫描扫描寻找大于寻找大于pivot的的元素元素i=low; j=high;r0=rlow; pivot=rlow.key;i ji =pivot-j;ri = rj;i j &ri.key=pivot-i;rj = ri;ri = r0;return ok;Y YY YY YN NN NN N一趟快速排序算法流程图一趟快速排序算法流程图一趟快速排序算法流程图一趟快速排序算法流程图39void QSort ( SqList &L, int lo
48、w, int high ) if ( low 1/对顺序表对顺序表L中的子序列中的子序列r lowhigh 作快速排序作快速排序/QSortvoid void Q QuickuickSortSort ( ( SqList SqList &L) &L) QSortQSort (L,(L, 1, L.length ); ); 对顺序表对顺序表对顺序表对顺序表L L进行快速进行快速进行快速进行快速排序的操作函数为:排序的操作函数为:排序的操作函数为:排序的操作函数为:40例例3:以关键字序列(以关键字序列(256,301,751,129,937,863,742,694,076,438)为例,写出执行
49、快速算法的)为例,写出执行快速算法的各趟各趟排排序结束时,关键字序列的状态。序结束时,关键字序列的状态。原始序列:原始序列: 256256,301301,751751,129129,937937,863863,742742,694694,076076,438438第第1趟趟第第2趟趟第第3趟趟第第4趟趟256256,301301,751751,129129,937937,863863,742742,694694,076076,438438076076076076,129129,256256256256,751751751751,937937,863863,742742,694694,30130
50、1,438438要求模拟算法实现步骤要求模拟算法实现步骤256256256256076076301301129129751751256256256256076076076076,129129,256256256256,438438,301301,694694,742742,694694,863863,937937751751751751076076076076,129129129129,256256256256,438438438438,301301,694694,742742,751751751751,863863863863,937937076076076076,129129129129,
51、256256256256,301301,301301,694694,742742,751751751751,863863863863,937937438438438438076076076076,129129129129,256256256256,301301301301,438438438438,694694694694,742742,751751751751,863863863863,937937937937时间效率:时间效率:时间效率:时间效率:O(nlogO(nlogO(nlogO(nlog2 2 2 2n)n)n)n)因为每趟确定的元素呈指数增加因为每趟确定的元素呈指数增加因为每趟确
52、定的元素呈指数增加因为每趟确定的元素呈指数增加空间效率:空间效率:空间效率:空间效率:O O O O(loglogloglog2 2 2 2n n n n)因为算法的递归性,要用到栈空间因为算法的递归性,要用到栈空间因为算法的递归性,要用到栈空间因为算法的递归性,要用到栈空间稳稳稳稳 定定定定 性:性:性:性:不稳定不稳定不稳定不稳定 因为可选任一元素为枢轴。因为可选任一元素为枢轴。因为可选任一元素为枢轴。因为可选任一元素为枢轴。41快速排序算法详细分析:快速排序算法详细分析:快速排序算法详细分析:快速排序算法详细分析:快速排序是递归的,需要有一个栈存放每层递快速排序是递归的,需要有一个栈存放
53、每层递归调用时的指针和参数归调用时的指针和参数(新的(新的lowlow和和highhigh)。可以证明,函数可以证明,函数quicksort的平均计算时间也是的平均计算时间也是O(nlog2n)。实验结果表明:就平均计算时间而实验结果表明:就平均计算时间而言,快速排序是我们所讨论的所有内排序方法中言,快速排序是我们所讨论的所有内排序方法中最好的一个最好的一个。最大递归调用层次数与递归树的深度一致,理最大递归调用层次数与递归树的深度一致,理想情况为想情况为 log2(n+1) 。因此,要求存储开销为因此,要求存储开销为 o(log2n)。42如果每次划分对一个对象定位后,该如果每次划分对一个对象
54、定位后,该对象的左侧子序列与右侧子序列的长对象的左侧子序列与右侧子序列的长度相同,则下一步将是对两个长度减度相同,则下一步将是对两个长度减半的子序列进行排序,这是最理想的半的子序列进行排序,这是最理想的情况。此时,快速排序的趟数最少。情况。此时,快速排序的趟数最少。43在最坏的情况,即待排序对象序列已经按其关键在最坏的情况,即待排序对象序列已经按其关键字从小到大排好序的情况下,字从小到大排好序的情况下,其递归树成为单支其递归树成为单支树树,每次划分只得到一个比上一次少一个对象的,每次划分只得到一个比上一次少一个对象的子序列。这样,必须经过子序列。这样,必须经过 n-1 趟才能把所有对象趟才能把
55、所有对象定位,而且第定位,而且第 i 趟需要经过趟需要经过 n-i 次关键字比较才次关键字比较才能找到第能找到第 i 个对象的安放位置,总的关键字比较个对象的安放位置,总的关键字比较次数将达到次数将达到n n2 2/2/2 快速排序是一个快速排序是一个不稳定不稳定的排序方法的排序方法44讨论讨论讨论讨论2. “2. “2. “2. “快速排序快速排序快速排序快速排序”是否真的比任何排序算法都快是否真的比任何排序算法都快是否真的比任何排序算法都快是否真的比任何排序算法都快?设每个子表的支点都在中间(比较均衡),则:设每个子表的支点都在中间(比较均衡),则:第第1 1趟比较,可以确定趟比较,可以确
56、定1 1个元素的位置;个元素的位置;第第2 2趟比较(趟比较(2 2个子表),可以再确定个子表),可以再确定2 2个元素的位置;个元素的位置;第第3 3趟比较(趟比较(4 4个子表),可以再确定个子表),可以再确定4 4个元素的位置;个元素的位置;第第4 4趟比较(趟比较(8 8个子表),可以再确定个子表),可以再确定8 8个元素的位置;个元素的位置; 只需只需 loglog2 2n n 1 1趟便可排好序。趟便可排好序。基本上是!因为每趟可以确定的数据元素是呈基本上是!因为每趟可以确定的数据元素是呈基本上是!因为每趟可以确定的数据元素是呈基本上是!因为每趟可以确定的数据元素是呈指数增加的!指
57、数增加的!指数增加的!指数增加的!45而且,每趟需要比较和移动的元素也呈指数下而且,每趟需要比较和移动的元素也呈指数下降,加上编程时使用了交替逼近技巧,更进一步降,加上编程时使用了交替逼近技巧,更进一步减少了移动次数,所以速度特别快。减少了移动次数,所以速度特别快。教材教材P276P276有证明:快速排序的平均排序效率有证明:快速排序的平均排序效率为为O(nlogO(nlog2 2n)n);但最坏情况但最坏情况( (例如已经有序例如已经有序) )下仍为下仍为O(nO(n2 2),),改改进措施见进措施见P277P277。46 选择排序的基本思想是:每一趟选择排序的基本思想是:每一趟 (例如第例
58、如第 i 趟,趟,i = 1, , n- -1) 在后面的在后面的 n- -i+1 个待排序对象中选出个待排序对象中选出关键字最小的对象关键字最小的对象, 作为有序对象序列的第作为有序对象序列的第 i 个对个对象。待到第象。待到第 n- -1 趟作完,待排序对象只剩下趟作完,待排序对象只剩下1个,个,就不用再选了。就不用再选了。10.4选择排序选择排序(Selection Sort)10.4.1 10.4.1 简单选简单选择排序择排序 10.4.2 10.4.2 树形选择排序树形选择排序10.4.3 10.4.3 堆排序堆排序4710.4.1 简单选简单选择排序择排序Simple Select
59、ion Sortn基本步骤为:基本步骤为:i从从1开始,直到开始,直到n-1,进行进行n-1趟排序,趟排序,第第i 趟的排序过程为:趟的排序过程为: 在一组对象在一组对象rirn (i=1,2,n-1)中选择具有最小关键字的对象;并和第中选择具有最小关键字的对象;并和第 i 个对象进行交换;个对象进行交换;48简单选择排序的算法简单选择排序的算法void SelectSort(SqList &L) for (int i=1; iL.length;+i) j=SelectMinKey(L,i); /在在L.ri.L.length中选择中选择key最小的记录最小的记录 if (i!=j) L.ri
60、L.rj;/与第与第i个记录交换个记录交换 4921212525494925*25*161608080 1 2 3 4 5212125*25*i = 1= 14949252516162525161608084949080825*25*49492121i = 2= 2i = 3= 30808161625*25*25252121初始初始初始初始最小者最小者 08交换交换21,08最小者最小者 16交换交换25,16最小者最小者 21交换交换49,2150494925*25*0 1 2 3 4 525*25*i = 5= 5252516160808494925*25*49492121结果结果i =
61、4= 40808161625252121最小者最小者 25*无交换无交换最小者最小者 25无交换无交换2525212116160808各趟排序后的结果各趟排序后的结果51算法分析算法分析 n直接选择排序的关键字比较次数直接选择排序的关键字比较次数KCN与对象与对象的初始排列无关。第的初始排列无关。第 i 趟选择具有最小关键字趟选择具有最小关键字对象所需的比较次数总是对象所需的比较次数总是 n- -i- -1 次,此处假定次,此处假定整个待排序对象序列有整个待排序对象序列有 n 个对象。因此,总个对象。因此,总的关键字比较次数为的关键字比较次数为时间复杂度?时间复杂度?O O(n n2 2)52
62、n对象的移动次数与对象序列的初始排列有关。当这对象的移动次数与对象序列的初始排列有关。当这组对象的初始状态是按其关键字从小到大有序的时组对象的初始状态是按其关键字从小到大有序的时候,对象的移动次数候,对象的移动次数RMN = 0,达到最少。达到最少。n最坏情况是每一趟都要进行交换,总的对象移动次最坏情况是每一趟都要进行交换,总的对象移动次数为数为RMN = 3(n- -1)。n直接选择排序是一种直接选择排序是一种不稳定不稳定的排序方法。的排序方法。5310.4.2 树形选择排序树形选择排序(锦标赛排序锦标赛排序 )n它的思想与体育比赛时的淘汰赛类似。首先取得它的思想与体育比赛时的淘汰赛类似。首
63、先取得 n 个对象的关键字,进行两两比较,得到个对象的关键字,进行两两比较,得到 n/2 个比较的优胜者个比较的优胜者(关键字小者关键字小者),作为第一步比较,作为第一步比较的结果保留下来。然后对这的结果保留下来。然后对这 n/2 个对象再进行个对象再进行关键字的两两比较,关键字的两两比较,如此重复,直到选出一,如此重复,直到选出一个关键字最小的对象为止。个关键字最小的对象为止。n在图例中,最下面是对象排列的初始状态,相当在图例中,最下面是对象排列的初始状态,相当于一棵满二叉树的叶结点,它存放的是所有参加于一棵满二叉树的叶结点,它存放的是所有参加排序的对象的关键字。排序的对象的关键字。5408
64、08Winner Winner 212108080808636325*25*212121212525494925*25*16160808636355胜者树的概念胜者树的概念n每每次次两两两两比比较较的的结结果果是是把把关关键键字字小小者者作作为为优优胜胜者者上上升到双亲结点,称这种比赛树为胜者树。升到双亲结点,称这种比赛树为胜者树。n胜者树最顶层是树的根,表示最后选择出来的具有胜者树最顶层是树的根,表示最后选择出来的具有最小关键字的对象。最小关键字的对象。560808Winner Winner ( (胜者胜者胜者胜者) )212108080808636325*25*21212121252549
65、4925*25*161608086363 形成初始胜者树(最小关键字上升到根)形成初始胜者树(最小关键字上升到根)a0关键字比较次数关键字比较次数 : 6 571616Winner Winner ( (胜者胜者胜者胜者) )212116161616636325*25*212121212525494925*25*16166363输出冠军并调整胜者树后树的状态输出冠军并调整胜者树后树的状态a1关键字比较次数关键字比较次数 : 2 582121Winner Winner ( (胜者胜者胜者胜者) )21216363636325*25*212121212525494925*25*6363输出亚军并调整
66、胜者树后树的状态输出亚军并调整胜者树后树的状态a2关键字比较次数关键字比较次数 : 2 592525Winner Winner ( (胜者胜者胜者胜者) )25256363636325*25*25252525494925*25*6363输出第三名并调整胜者树后树的状态输出第三名并调整胜者树后树的状态a3关键字比较次数关键字比较次数 : 2 6025*25*Winner Winner ( (胜者胜者胜者胜者) )25*25*6363636325*25*494925*25*6363输出第四名并调整胜者树后树的状态输出第四名并调整胜者树后树的状态a4关键字比较次数关键字比较次数 : 2 616363
67、Winner Winner ( (胜者胜者胜者胜者) )636363636363全部比赛结果输出时树的状态全部比赛结果输出时树的状态a6关键字比较次数关键字比较次数 : 2 62算法分析算法分析n锦标赛排序构成的树是满的完全二叉树,其深度为锦标赛排序构成的树是满的完全二叉树,其深度为 log2(n+1) ,其中其中 n 为待排序元素个数。为待排序元素个数。n除第一次选择具有最小关键字的对象需要进行除第一次选择具有最小关键字的对象需要进行 n-1 次次关键字比较外,重构胜者树选择具有次小、再次小关关键字比较外,重构胜者树选择具有次小、再次小关键字对象所需的关键字比较次数均为键字对象所需的关键字比
68、较次数均为 O(log2n)。总关总关键字比较次数为键字比较次数为O(nlog2n)。n对象的移动次数不超过关键字的比较次数,所以锦标对象的移动次数不超过关键字的比较次数,所以锦标赛排序总的时间复杂度为赛排序总的时间复杂度为O(nlog2n)。n这种排序方法虽然减少了许多排序时间,但是使用了这种排序方法虽然减少了许多排序时间,但是使用了较多的附加存储。较多的附加存储。锦标赛排序是一个稳定的排序方法。锦标赛排序是一个稳定的排序方法。6310.4.3 堆排序堆排序 (Heap Sort)n利用堆及其运算,可以很容易地实现选择排利用堆及其运算,可以很容易地实现选择排序的思路。堆排序分为两个步骤:第一
69、步,序的思路。堆排序分为两个步骤:第一步,根据初始输入数据,利用堆的调整算法根据初始输入数据,利用堆的调整算法 HeapAdjust ( ) 形成初始堆,第二步,通过一形成初始堆,第二步,通过一系列的对象交换和重新调整堆进行排序。系列的对象交换和重新调整堆进行排序。n给定一组关键字,初始态存储时是一个完全给定一组关键字,初始态存储时是一个完全二叉树二叉树n堆的建立堆的建立n对堆的筛选与建立的重复交替对堆的筛选与建立的重复交替64堆排序堆排序 (Heap Sort)n给定一组关键字,初始态存储时是一个完全二给定一组关键字,初始态存储时是一个完全二叉树叉树n小顶堆的建立:小顶堆的建立: 对对 n/
70、2 1,的元素依次进行筛选:的元素依次进行筛选:u若若ki=k2i且且kik2i(k2i+1)且且kik2i且且kik2i+1,则,则ki与与较小的哪个交换较小的哪个交换u若若(k2i=k2i+1) ki,则则ki与与k2i交换交换(大顶堆刚好相反)(大顶堆刚好相反)n对堆的筛选与建立的重复交替对堆的筛选与建立的重复交替65建立初始的最大堆建立初始的最大堆2121252525*25*494916160808123456i2121252525*25*161649490808136542i21 25 49 25* 16 0821 25 49 25* 16 08初始关键字集合初始关键字集合21 25
71、 49 25* 16 0821 25 49 25* 16 08i = 3 时的局部调整时的局部调整662121252525*25*494916160808123456i4949252525*25*16162121080813654221 25 49 25* 16 0821 25 49 25* 16 0849 25 21 25* 16 0849 25 21 25* 16 08i = 1 时的局部调整时的局部调整形成大顶堆形成大顶堆i = 2 时的局部调整时的局部调整67最大堆的向下调整算法最大堆的向下调整算法void HeapAdjust(HeapType &H,int s,int m) Ele
72、mType rc=H.rs; for (int j=2*s;j=m;j*=2) if (j0; -i) HeapAdjust(H,i,H.length); for (i=H.length; i1; -i) temp=H.r1;H.r1=H.ri;H.ri=temp;HeapAdjust(H,1,i-1); 75算法分析算法分析n若设堆中有若设堆中有 n 个结点,且个结点,且 2k- -1 n 2k,则对应的完则对应的完全二叉树有全二叉树有 k 层。在第层。在第 i 层上的结点数层上的结点数 2i-1 (i = 1, , k)。在第一个形成初始堆的在第一个形成初始堆的for循环中对每一个非循环中
73、对每一个非叶结点调用了一次堆调整算法叶结点调用了一次堆调整算法HeapAdjust ( ),因此因此该循环所用的计算时间为:该循环所用的计算时间为:n其中,其中,i 是层序号,是层序号,2i-1 是第是第 i 层的最大结点数,层的最大结点数,(k- -i- -1)是第是第 i 层结点能够移动的最大距离。层结点能够移动的最大距离。76n在第二个在第二个for循环中,调用了循环中,调用了n- -1次次HeapAdjust ( )算算法,该循环的计算时间为法,该循环的计算时间为O(nlog2n)。因此,堆排序的因此,堆排序的时间复杂性为时间复杂性为O(nlog2n)。n该算法的附加存储主要是在第二个
74、该算法的附加存储主要是在第二个for循环中用来执行循环中用来执行对象交换时所用的一个临时对象。因此,该算法的空对象交换时所用的一个临时对象。因此,该算法的空间复杂性为间复杂性为O(1)。n堆排序是一个不稳定的排序方法。堆排序是一个不稳定的排序方法。7710.5 10.5 归并排序归并排序 基基本本思思想想:将将一一个个具具有有n个个待待排排序序记记录录的的序序列列看看成成是是n个个长长度度为为1的的有有序序列列,然然后后进进行行两两两两归归并并,得得到到n/2 个个长长度度为为2的的有有序序序序列列,再再进进行行两两两两归归并并,得得到到n/4 个个长长度度为为4的的有有序序序序列列,如如此此
75、重重复复,直直至至得得到到一一个个长长度度为为n的的有有序序序序列为止列为止 78归并排序示例归并排序示例二趟归并排序后二趟归并排序后: 33 51 62 96 1 17 28 87 初始关键字序列初始关键字序列: 51 33 62 96 87 1728 一趟归并排序后一趟归并排序后: 33 51 62 96 117 87 28 三趟归并排序后三趟归并排序后: 17 28 33 51 62 87 96 79归并排序示例归并排序示例80算法分析算法分析n在在归归并并排排序序算算法法中中,对对象象关关键键字字的的比比较较次次数数为为O(nlog2n)。算法总的时间复杂度为算法总的时间复杂度为O(n
76、log2n)。n归归并并排排序序占占用用附附加加存存储储较较多多,需需要要另另外外一一个个与与原原待待排排序序对对象象数数组组同同样样大大小小的的辅辅助助数数组组。这这是是这这个个算算法法的的缺缺点。点。n归并排序是一个稳定的排序方法。归并排序是一个稳定的排序方法。8110.6 基数排序基数排序 (Radix Sort)n基数排序是采用基数排序是采用“分配分配”与与“收集收集”的办法,用对多的办法,用对多关键字进行排序的思想实现对单关键字进行排序的方关键字进行排序的思想实现对单关键字进行排序的方法。法。10.6.1 多关键字排序多关键字排序n以以扑扑克克牌牌排排序序为为例例。每每张张扑扑克克牌
77、牌有有两两个个“关关键键字字”:花色和面值。其有序关系为:花色和面值。其有序关系为:u 花色:花色: u 面面值值:2 3 4 5 6 7 8 9 10 J Q K An如果我们把所有扑克牌排成以下次序:如果我们把所有扑克牌排成以下次序:u 2, , A, 2, , A, 2, , A, 2, , A82n这就是这就是多关键字排序多关键字排序。排序后形成的有序序列叫做词。排序后形成的有序序列叫做词典有序序列。典有序序列。n对于上例两关键字的排序,可以先按花色排序,之后对于上例两关键字的排序,可以先按花色排序,之后再按面值排序;也可以先按面值排序,再按花色排序。再按面值排序;也可以先按面值排序,
78、再按花色排序。n一般情况下,假定有一个一般情况下,假定有一个 n 个对象的序列个对象的序列 V0, V1, , Vn-1 ,且每个对象且每个对象Vi 中含有中含有 d 个关键字个关键字n如果对于序列中任意两个对象如果对于序列中任意两个对象 Vi 和和 Vj ( 0 i j n-1 ) 都满足:都满足:83n则称序列对关键字则称序列对关键字 (K1, K2, , Kd) 有序。其中,有序。其中,K1 称为最高位关键字,称为最高位关键字,Kd 称为最低位关键字。称为最低位关键字。n如果关键字是由多个数据项组成的数据项组,则依据如果关键字是由多个数据项组成的数据项组,则依据它进行排序时就需要利用多关
79、键字排序。它进行排序时就需要利用多关键字排序。n实现多关键字排序有两种常用的方法实现多关键字排序有两种常用的方法u最高位优先最高位优先MSD (Most Significant Digit first)u最低位优先最低位优先LSD (Least Significant Digit first)n最高位优先法最高位优先法通常是一个递归的过程:通常是一个递归的过程:u 先根据先根据最高位关键字最高位关键字K1排序排序,得到若干对象得到若干对象组,对象组中每个对象都有相同组,对象组中每个对象都有相同关键字关键字K1。 84u 再再分分别别对对每每组组中中对对象象根根据据关关键键字字K2进进行行排排序
80、序,按按K2值值的的不不同同,再再分分成成若若干干个个更更小小的的子子组,每个子组中的对象具有相同的组,每个子组中的对象具有相同的K1和和K2值。值。u 依此重复,直到对依此重复,直到对关键字关键字Kd完成排序为止。完成排序为止。u 最最后后,把把所所有有子子组组中中的的对对象象依依次次连连接接起起来来,就得到一个有序的对象序列。就得到一个有序的对象序列。85n最最低低位位优优先先法法首首先先依依据据最最低低位位关关键键字字KdKd对对所所有有对对象象进进行行一一趟趟排排序序,再再依依据据次次低低位位关关键键字字KdKd-1-1对对上上一一趟趟排排序序的的结结果果再再排排序序,依依次次重重复复
81、,直直到到依依据据关关键键字字K K1 1最最后后一一趟趟排排序序完完成成,就就可可以以得得到到一一个个有有序序的的序序列列。使使用用这这种种排排序序方方法法对对每每一一个个关关键键字字进进行行排排序序时时,不不需需要要再再分分组组,而而是是整整个个对对象象组组都都参参加加排排序。序。86nLSD和和MSD方法也可应用于对一个关键字进行的方法也可应用于对一个关键字进行的排序。此时可将排序。此时可将单关键字单关键字 Ki 看作是一个子关键字看作是一个子关键字组组:87n基基数数排排序序是是典典型型的的LSD排排序序方方法法,利利用用“分分配配”和和“收收集集”两两种种运运算算对对单单关关键键字字
82、进进行行排排序序。在在这这种种方方法法中中,把把单单关关键键字字 Ki 看看成是一个成是一个d元组元组:n其其中中的的每每一一个个分分量量 ( 1 j d ) 也也可可看看成成是一个关键字。是一个关键字。10.6.2 链式基数排序链式基数排序88n分分量量 (1 j d ) 有有radix种种取取值值,则则称称radix为为基基数数。例例如如,关关键键字字984可可以以看看成成是是一一个个3元元组组(9, 8, 4),每每一一位位有有0, 1, , 9等等10种种取取值值,基基数数radix = 10。关关键键字字data可可以以看看成成是是一一个个4元元组组(d, a, t, a),每每一一
83、位位有有a, b, , z等等26种种取取值值,radix = 26。n针针对对d元元组组中中的的每每一一位位分分量量,把把对对象象序序列列中中的的所所有有对对象象, 按按 的的取取值值,先先“分分配配”到到rd个个队队列列中中去去。然然后后再再按按各各队队列列的的顺顺序序,依依次次把把对对象象从从队队列列中中“收收集集”起起来,这样所有对象按取值来,这样所有对象按取值 排序完成。排序完成。89n如果对于所有对象的关键字如果对于所有对象的关键字K0, K1, , Kn-1,依依次对各位的分量,让次对各位的分量,让 j = d, d- -1, , 1,分别用这分别用这种种“分配分配”、“收集收集
84、”的运算逐趟进行排序,在的运算逐趟进行排序,在最后一趟最后一趟“分配分配”、“收集收集” 完成后,所有对完成后,所有对象就按其关键字的值从小到大排好序了。象就按其关键字的值从小到大排好序了。n各队列采用链式队列结构,分配到同一队列的关各队列采用链式队列结构,分配到同一队列的关键字用链接指针链接起来。每一队列设置两键字用链接指针链接起来。每一队列设置两 个个队列指针:队列指针: int front radix指示队头,指示队头, int rear radix 指向队尾。指向队尾。90 为了有效地存储和重排为了有效地存储和重排 n n 个待排序个待排序对象,以对象,以静态链表静态链表作为它们的存储
85、结构。作为它们的存储结构。在对象重排时不必移动对象,只需修改各在对象重排时不必移动对象,只需修改各对象的链接指针即可。对象的链接指针即可。91例例1 1初始状态:278109063930589184505269008083109589269278063930083184505008e0e1e2e3e4e5e6e7e8e9f0f1f2f3f4f5f6f7f8f9一趟分配930063083184505278008109589269一趟收集:静态链表静态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第一趟一趟92505008109930063269278083184589二趟收集:
86、083184589063505269930e0e1e2e3e4e5e6e7e8e9f0f1f2f3f4f5f6f7f8f9二趟分配008109278930063083184505278008109589269一趟收集:静态链表静态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第二趟二趟93008063083109184269278505589930三趟收集:109008184930e0e1e2e3e4e5e6e7e8e9f0f1f2f3f4f5f6f7f8f9三趟分配063083269278505589505008109930063269278083184589二趟收集:静态
87、链表静态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第三趟三趟94静态链表静态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第一趟一趟614921485637738101215530790306第一趟分配(按最低位第一趟分配(按最低位第一趟分配(按最低位第一趟分配(按最低位 i i = 3 = 3 )re0 re1 re2 re3 re4 re5 re6 re7 re8 re9614738921485637101215530790306fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9第一趟收集第一趟收集第一趟收集第一趟收集53
88、0790921101614485215306637738例例2 295静态链表静态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第二趟二趟614921485637738101215530790306第二趟分配(按次低位第二趟分配(按次低位第二趟分配(按次低位第二趟分配(按次低位 i i = 2 = 2 )re0 re1 re2 re3 re4 re5 re6 re7 re8 re9614738921485637101215530790306fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9第二趟收集第二趟收集第二趟收集第二趟收集5307909211
89、0161448521530663773896静态链表静态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第三趟三趟614921485637738101215530790306第三趟分配(按最高位第三趟分配(按最高位第三趟分配(按最高位第三趟分配(按最高位 i i = 1 = 1 )re0 re1 re2 re3 re4 re5 re6 re7 re8 re9614738921485637101215530790306fr0 fr1 fr2 fr3 fr4 fr5 fr6 fr7 fr8 fr9第三趟收集第三趟收集第三趟收集第三趟收集53079092110161448521530
90、663773897算法分析算法分析n若若每每个个关关键键字字有有d 位位,需需要要重重复复执执行行d 趟趟“分分配配”与与“收收集集”。每每趟趟对对 n 个个对对象象进进行行“分分配配”,对对radix个个队队列列进进行行“收收集集”。总总时时间间复复杂杂度度为为O ( d ( n+radix ) )。n若若基基数数radix相相同同,对对于于对对象象个个数数较较多多而而关关键键字字位位数数较少的情况,使用链式基数排序较好。较少的情况,使用链式基数排序较好。n基数排序需要增加基数排序需要增加n+2radix个附加链接指针。个附加链接指针。n基数排序是稳定的排序方法。基数排序是稳定的排序方法。9
91、8初始状态:初始状态:12781090639305891845052690080832345678910f0=0 e0=0f1=0 e1=0f2=0 e2=0f3=0 e3=0f4=0 e4=0f5=0 e5=0f6=0 e6=0f7=0 e7=0f8=0 e8=0f9=0 e9=01122334456677891049300630831845052780081095892693106719258动态链表动态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第一趟一趟99f0=0 e0=0f1=0 e1=0f2=0 e2=0f3=0 e3=0f4=0 e4=0f5=0 e5=0f
92、6=0 e6=0f7=0 e7=0f8=0 e8=0f9=0 e9=013447791049300630831845052780081095892693106719258一趟收集:一趟收集:3101625875050081099300632692780831845899243811065二趟收集:二趟收集:动态链表动态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第二趟二趟10075050081099300632692780831845899243811065二趟收集:二趟收集:f0=0 e0=0f1=0 e1=0f2=0 e2=0f3=0 e3=0f4=0 e4=0f5=0
93、 e5=0f6=0 e6=0f7=0 e7=0f8=0 e8=0f9=0 e9=0447928792890080630831091842692785055899303102681754三趟收集:三趟收集:311065动态链表动态链表基数排序的基数排序的“分配分配”与与“收集收集”过程过程 第第三趟三趟101小结小结 需要复习的知识点需要复习的知识点n n排序的基本概念排序的基本概念排序的基本概念排序的基本概念u 排序的基本概念排序的基本概念u 关键字、初始关键字排列关键字、初始关键字排列u 关键字比较次数、数据移动次数关键字比较次数、数据移动次数u 稳定性稳定性u 附加存储附加存储n n插入排
94、序插入排序插入排序插入排序u直接插入排序和折半插入排序、希尔排序的直接插入排序和折半插入排序、希尔排序的算法算法用例子说明直接插入排序、折半插入排序、希用例子说明直接插入排序、折半插入排序、希尔排序的过程尔排序的过程 排序的性能分析排序的性能分析 102快速排序快速排序u 起泡排序和快速排序的算法起泡排序和快速排序的算法 u 用例子表明起泡排序和快速排序的过程用例子表明起泡排序和快速排序的过程u快速排序的快速排序的递归算法递归算法和和非递归算法非递归算法 快速排序是一个递归的排序法快速排序是一个递归的排序法 当待排序关键字序列已经基本有序时,快速当待排序关键字序列已经基本有序时,快速排序显著变
95、慢。排序显著变慢。选择排序选择排序u 简单选择排序和堆排序的算法简单选择排序和堆排序的算法u 用例子表明简单选择排序、树形排序、堆排用例子表明简单选择排序、树形排序、堆排序的过程序的过程103u三种选择排序的性能分析三种选择排序的性能分析 用简单选择排序在一个待排序区间中选出最小用简单选择排序在一个待排序区间中选出最小的数据时,与区间第一个数据对调,不是顺次的数据时,与区间第一个数据对调,不是顺次后移。这导致方法不稳定。后移。这导致方法不稳定。 当在当在 n 个数据(个数据(n很大)中选出最小的很大)中选出最小的 5 8 个个数据时,树形选择最快。数据时,树形选择最快。树形选择排序算法将待排序
96、数据个数树形选择排序算法将待排序数据个数 n 补足到补足到 2的的 k 次幂次幂 2k- -1 n 2k 在堆排序中将待排序的数据组织成完全二叉在堆排序中将待排序的数据组织成完全二叉树的顺序存储。树的顺序存储。104 n n归并排序归并排序归并排序归并排序u 归并排序算法归并排序算法u 用例子表明归并排序的过程用例子表明归并排序的过程u 该算法的性能分析该算法的性能分析 归并排序可以递归执行归并排序可以递归执行 归并排序需要较多的附加存储。归并排序需要较多的附加存储。 105归并排序对待排序关键字的初始排列不敏感,归并排序对待排序关键字的初始排列不敏感,故排序速度较稳定。故排序速度较稳定。106排排 序序 方方 法法 时间复杂度时间复杂度稳定稳定 性性 附加存储附加存储直接插入排序直接插入排序O(n2) 1折半插入排序折半插入排序O(n log2n) 1起泡排序起泡排序O(n2) 1快速排序快速排序O(nlog2n) log2n 简单选择排序简单选择排序O(n2) 1树形排序树形排序O(n log2n) n堆排序堆排序O(n log2n) 1归并排序归并排序O(n log2n) n基数排序基数排序O(d(n+rd) rd各种排序方法的比较各种排序方法的比较107