1、10.1 概述 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序,第十章 排序,10.1 概述,1. 什么是排序?,排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。,例将下列关键字序列52, 49, 80, 36, 14, 58, 61, 23, 97, 75调整为14, 23, 36, 49, 52, 58, 61 ,75, 80, 97,一般情况下, 假设含n个记录的序列为 R1, R2, , Rn 其相应的关键字序列为 K1, K2, ,Kn 这些关键字相互之间可以进行比较,即在它们之间存在着这样一个关系Kp1Kp
2、2Kpn 按此固有关系将式(1)的记录序列重新排列为 Rp1, Rp2, ,Rpn 的操作称作排序。,10.1 概述,稳定/不稳定,2.内部排序和外部排序,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序; 反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。,3.内部排序的方法,内部排序的过程是一个逐步扩大记录的有序序列长度的过程。在排序的过程中,参与排序的记录序列中存在两个区域:有序区和无序区。,使有序区中记录的数目增加一个或几个的操作称为一趟排序。,逐步扩大记录有序序列长度的方法大致有下列几类:,1.插入类 将无序子序列中的一
3、个或几个记录“插入”到有序序列中,从而增加记录的有序子序列的长度;,2.交换类 通过“交换”无序序列中的记录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度;,3.选择类 从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度;,4.归并类 通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度;,5.基数排序类,按排序所需工作量 简单的排序方法:T(n)=o(n) 先进的排序方法:T(n)=o(nlogn) 基数排序:T(n)=o(d.n)排序基本操作 比较两个关键字大小
4、 将记录从一个位置移动到另一个位置,10.2 插入排序,假设在排序过程中,记录序列R1n的状态为:,一趟直接插入排序的基本思想为:将记录Ri插入到有序子序列R1i-1中,使记录的有序序列从R1i-1变为R1i。,完成这个“插入”需分三步进行: 1查找Ri的插入位置j+1; 2将Rj+1i-1中的记录后移一个位置; 3将Ri复制到Rj+1的位置上。,一、直接插入排序利用顺序查找实现“在R1i-1中查找Ri的插入位置”,三个要点:,1.从Ri-1起向前进行顺序查找,监视哨设置在R0;R0 = Ri; / 设置“哨兵”for (j=i-1; R0.keyRj.key; -j); / 从后往前找ret
5、urn j+1; / 返回Ri的插入位置为j+1,2对于在查找过程中找到的那些关键字不小于Ri.key的记录,并在查找的同时实现记录向后移动;for (j=i-1; R0.keyRj.key; -j) Rj+1 = Rj,3i = 2,3,, n, 实现整个序列的排序。,直接插入排序算法描述:,例,49 38 65 97 76 13 27,i=2 38 (38 49) 65 97 76 13 27,i=3 65 (38 49 65) 97 76 13 27,i=4 97 (38 49 65 97) 76 13 27,i=5 76 (38 49 65 76 97) 13 27,i=6 13 (1
6、3 38 49 65 76 97) 27,i=7 (13 38 49 65 76 97) 27,27,97,76,65,49,38,27,直接插入排序算法评价 时间复杂度最好情况:待排序记录按关键字从小到大排列 关键字比较次数:,记录移动次数:,最坏情况:待排序记录按关键字从大到小排列 关键字比较次数:,记录移动次数:,T(n)=O(n),空间复杂度:S(n)=O(1),0,二、折半插入排序,因为R1i-1是一个按关键字有序的有序序列,则可以利用折半查找实现“在R1i-1中查找Ri的插入位置”,例,i=2 30 (13 30) 70 85 39 42 6 20,i=7 6 (6 13 30 3
7、9 42 70 85 ) 20,.,i=8 20 (6 13 20 30 39 42 70 85 ),二、折半插入排序,因为R1i-1是一个按关键字有序的有序序列,则可以利用折半查找实现“在R1i-1中查找Ri的插入位置”,如此实现的插入排序为折半插入排序。,折半插入排序比直接插入排序明显地减少了关键字间的“比较”次数,但记录“移动”的次数不变。,空间复杂度:S(n)=O(1),时间复杂度:T(n)=O(n),算法描述,void BiInsertionSort (Elem R , int n) for ( i=2; i=high+1; -j ) Rj+1 = Rj; / 记录后移Rhigh+1
8、 = R0; / 插入 / BInsertSort,四、希尔排序(又称缩小增量排序),基本思想:对待排记录序列先作“宏观”调整,再作“微观”调整。,所谓“宏观”调整,指的是,“跳跃式”的插入排序。即:将记录序列分成若干子序列,每个子序列分别进行插入排序。关键是,这种子序列不是由相邻的记录构成的。,假设将n个记录分成d个子序列,则这d个子序列分别为: R1,R1+d,R1+2d,R1+kd R2,R2+d,R2+2d,R2+kd Rd,R2d,R3d,Rkd,R(k+1)d 其中,d称为增量,它的值在排序过程中从大到小逐渐缩小,直至最后一趟排序减为1。,void ShellInsert ( El
9、em R, int dk ) / 对R作一趟希尔插入排序。本算法对直接插入算法作了以下修改: /1. 前后记录位置的增量是dk,而不是1; / 2. r0只是暂存单元,不是哨兵。当j0 / 插入 / ShellInsert,void ShellSort (Elem R, int dlta, int t) / 按增量序列dlta0t-1对顺序表L作希尔排序。for (k=0; kt; +t)ShellInsert(R, dltak); / 一趟增量为dltak的插入排序 / ShellSort,#define T 3 int d=5,3,1;,49,13,38,27,27,4,55,38,65,
10、48,97,55,76,4,希尔排序特点 子序列的构成不是简单的“逐段分割”,而是将相隔某个增量的记录组成一个子序列 希尔排序可提高排序速度,因为 分组后n值减小,n更小,而T(n)=O(n),所以T(n)从总体上看是减小了 关键字较小的记录跳跃式前移,在进行最后一趟增量为1的插入排序时,序列已基本有序 增量序列取法 无除1以外的公因子 最后一个增量值必须为1,不稳定 ,如:3 2 2 4 d =2,1;,10.3 快速排序,它属交换排序,其中最简单的一种交换排序是:起泡排序,1. 起泡排序,假设在排序过程中,记录序列R1n的状态为:,则第i趟起泡插入排序的基本思想为:借助对无序序列中的记录进
11、行“交换”的操作,将无序序列中关键字最大的记录“交换”到Rn-i+1的位置上。,起泡排序过程 将第一个记录的关键字与第二个记录的关键字进行比较,若为逆序r1.keyr2.key,则交换;然后比较第二个记录与第三个记录;依次类推,直至第n-1个记录和第n个记录比较为止第一趟冒泡排序,结果关键字最大的记录被安置在最后一个记录上 对前n-1个记录进行第二趟冒泡排序,结果使关键字次大的记录被安置在第n-1个记录位置 重复上述过程,直到“在一趟排序过程中没有进行过交换记录的操作”为止,起泡排序的结束条件为:最后一趟没有进行“交换”。,时间分析:,最好的情况(关键字顺序有序):只需进行一趟起泡 “比较”的
12、次数: “移动”的次数:n-1 0 最坏的情况(关键字逆序有序):需进行n-1趟起泡 “比较”的次数: “移动”的次数:,T(n)=O(n),从起泡排序的过程可见,起泡排序是一个增加有序序列长度的过程,也是一个缩小无序序列长度的过程,每经过一趟起泡,无序序列的长度只缩小1。,若能在经过一趟排序,使无序序列的长度缩小一半,则必能加快排序的速度。,二、一趟快速排序,目标:找一个记录,以它的关键字作为“枢轴”,凡其关键字小于枢轴的记录均移动至该记录之前,反之,凡关键字大于枢轴的记录均移动至该记录之后。致使一趟排序之后,记录的无序序列Rst将分割成两部分:Rsi-1和Ri+1t,且Rj.key Ri.
13、key Rj.key(sji-1) 枢轴 (i+1jt),例如:关键字序列 52, 49, 80, 36, 14, 58, 61, 97, 23, 75 调整为: 23, 49, 14, 36, (52) 58, 61, 97, 80, 75 其中(52)为枢轴,在调整过程中,需设立两个指针: low和high,它们的初值分别为:s和t, 之后逐渐减小high,增加low,并保证Rhigh.key52,而Rlow.key52, 否则进行记录的“交换”。,10.3 快速排序,三、快速排序过程,在对整个无序序列中记录进行了一次分割之后,分别对分割所得两个子序列进行快速排序,依次类推,直至每个子序列
14、中只含一个记录为止。,每趟排序均有一个记录放到其最终位置,完成一趟排序: ( 27 38 13) 49 (76 97 65 50),分别进行快速排序: ( 13) 27 (38) 49 (50 65) 76 (97),快速排序结束: 13 27 38 49 50 65 76 97,49,27,49,65,13,49,49,97,不稳定,如3 4 2 2,int Partition (Elem R, int low, int high) / 交换记录子序列Rlowhigh中的记录,使枢轴记录到位,并返回其所在位置,此时,在它之前(后)的记录均不大(小)于它 pivotkey = Rlow.key
15、; while (low=pivotkey) -high;RlowRhigh; / 将比枢轴记录小的记录交换到低端while (lowhigh / 返回枢轴所在位置 / Partition,int Partition (Elem R, int low, int high) R0 = Rlow; / 用子表的第一个记录作枢轴记录 pivotkey = Rlow.key; / 枢轴记录关键字 while (low=pivotkey) -high;Rlow = Rhigh; / 将比枢轴记录小的记录移到低端while (lowhigh / 返回枢轴位置 / Partition,10.4 选择排序,假
16、设排序过程中,待排记录序列的状态为:,并且有序序列中所有记录的关键字均小于无序序列中记录的关键字,则第i趟简单选择排序是,从无序序列Rin的n-i+1记录中选出关键字最小的记录加入有序序列。,排序过程 首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换 再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换 重复上述操作,共进行n-1趟排序后,排序结束,一、简单选择排序,例,初始: 49 38 65 97 76 13 27 ,i=1,13,49,一趟: 13 38 65 97 76 49 27 ,i=2,27,38,六趟: 13 2
17、7 38 49 65 76 97 ,排序结束: 13 27 38 49 65 76 97,简单选择排序的算法描述如下:,时间性能分析,对n个记录进行简单选择排序,所需进行的关键字间的比较次数总计为:,移动记录的次数,最小值为0, 最大值为3(n-1),10.4 选择排序,二、堆排序,堆排序的特点是,在以后各趟的“选择”中 利用在第一趟选择中已经得到的关键字比较的结果。,堆的定义:堆是满足下列性质的数列r1, r2, ,rn:,可将堆序列看成完全二叉树,则堆顶 元素(完全二叉树的根)必为序列中 n个元素的最小值或最大值,例 (96,83,27,38,11,9),例 (13,38,27,50,76
18、,65,49,97),堆排序:将无序序列建成一个堆,得到关键字最小(或最大)的记录;输出堆顶的最小(大)值后,使剩余的n-1个元素重又建成一个堆,则可得到n个元素的次小值;重复执行,得到一个有序序列,这个过程叫堆排序 堆排序需解决的两个问题: 如何由一个无序序列建成一个堆? 如何在输出堆顶元素之后,调整剩余元素,使之成为一个新的堆? 第二个问题解决方法筛选 方法:输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换;重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”,二、堆排序,例,二、堆排序,第一个问题解
19、决方法 方法:从无序序列的第n/2个元素(即此无序序列对应的完全二叉树的最后一个非终端结点)起,至第一个元素止,进行反复筛选,二、堆排序,例 含8个元素的无序序列(49,38,65,97,76,13,27,50),堆排序的时间复杂度为o(nlogn),10.5 归并排序,归并排序的基本思想是:将两个或两个以上的有序子序列“归并”为一个有序序列。,在内部排序中,通常采用的是2-路归并排序。即:将两个位置相邻的有序子序列归并为一个有序序列。,排序过程 设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1 两两合并,得到n/2 个长度为2或1的有序子序列 再两两合并,如此重复,直至得
20、到一个长度为n的有序序列为止,例,初始关键字: 49 38 65 97 76 13 27,一趟归并后: 38 49 65 97 13 76 27,二趟归并后: 38 49 65 97 13 27 76,三趟归并后: 13 27 38 49 65 76 97,10.5 归并排序,10.7 各种内部排序方法的综合比较,一、时间性能,1.按平均的时间性能来分,有三类排序方法: 时间复杂度为o(nlogn)的方法有:快速排序、堆排序和归并排序,其中以快速排序为最好;时间复杂度为o(n2)的有:直接插入排序、起泡排序和简单选择排序,其中以直接插入为最好,特别是对那些对关键字近似有序的记录序列尤为如此;
21、时间复杂度为O(n)的排序方法只有,基数排序。,2.当待排记录序列按关键字顺序有序时,直接插入排序和起泡排序能达到o(n)的时间复杂度;而对于快速排序而言,这是最不好的情况,此时的时间性能蜕化为o(n2),因此是应该尽量避免的情况。 3.简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。,二、空间性能,指的是排序过程中所需的辅助空间大小。 1. 所有的简单排序方法(包括:直接插入、起泡和简单选择)和堆排序的空间复杂度为o(1); 2. 快速排序为o(logn ),为栈所需的辅助空间; 3. 归并排序所需辅助空间最多,其空间复杂度为o(n ),三、排序方法的稳定性能 P289 (4),学习要点,1. 深刻理解排序的定义和各种排序方法的特点,并能加以灵活应用。2. 了解各种方法的排序过程及其依据的原则。基于“关键字间的比较”进行排序的方法可以按排序过程所依据的不同原则分为插入排序、交换排序、选择排序、归并排序和计数排序等五类。3. 掌握各种排序方法的时间复杂度的分析方法。能从“关键字间的比较次数”分析排序算法的平均情况和最坏情况的时间性能。,