1、第六章 排序,概述插入排序交换排序选择排序归并排序分配排序外排序,6.1 概述 什么是排序(Sorting)?,简单地说,排序就是将一组杂乱无章的数据按一定的规律排列起来(递增或递减)。排序是计算机中经常遇到的操作。,排序的几个基本概念,数据表(Data List) 待排序的数据对象的有限集合。 关键字(Key) 作为排序依据的数据对象中的属性域。 排序的确切定义 使一组任意排列的对象变成一组按关键字线性有序的对象。,排序的几个基本概念(续),排序算法的稳定性 判断标准:关键字相同的数据对象在排序过程中是否保持前后次序不变。如 2, 2*,1,排序后若为1, 2*, 2 则该排序方法是不稳定的
2、。 内排序与外排序 区分标准:排序过程是否全部在内存进行。 内排序方法可以分为五类:插入排序、选择排序、交换排序、归并排序和分配排序。,三种存储结构:一维数组、链表和辅助表。排序的方法有很多,但简单地判断那一种算法最好,以便能够普遍选用则是困难的。评价排序算法好坏的标准主要有两条:算法执行所需要的时间和所需要的附加空间。另外,算法本身的复杂程度也是需要考虑的一个因素。,排序的几个基本概念(续1),排序的几个基本概念(续2),排序算法所需要的附加空间一般都不大,矛盾并不突出。而排序是一种经常执行的一种运算,往往属于系统的核心部分,因此排序的时间开销是算法好坏的最重要的标志。 排序的时间开销 它是
3、衡量算法好坏的最重要的标志。通常用算法执行中的数据比较次数和数据移动次数来衡量。,为简单起见,数据的存储结构采用记录数组形式,同时假定关键字是整数。记录数组的类型说明如下:,typedef struct int key;datatype other; rectype;rectype Rn;,其中n为记录总数加1,基本思想 算法 执行过程 复杂度,6.2 插入排序,基本原理,每步将一个待排序的对象,按其关键字大小,插入到前面已经排好序的一组对象适当位置上,直到对象全部插入为止。,直接插入排序(Insert Sort) 希尔排序(Shell Sort),直接插入排序(Insert Sort),基本
4、思想:当插入第i个对象时,前面的R1,R2,Ri-1已经排好序,此时,用Ri的关键字与Ri-1, Ri-2,的关键字顺序进行比较,找到插入位置即将Ri插入,原来位置上对象向后顺移。,直接插入排序算法 INSERTSORT(rectype R) int i,j;for (i=2;in;i+) R0Ri;ji-1;while (R0.keyRj.key) Rj+1Rj-;Rj+1R0; ,算法中引入附加记录R0有两个作用:其一是进入查找循环之前,它保存了Ri的副本,使得不至于因记录的后移而丢失Ri中的内容;其二是在while循环“监视”下标变量j是否越界,一旦越界(即j=1)。因此,我们把R0称为
5、“监视哨”。,直接插入排序举例,i (1) (2) (3) (4) (5) (6) (0)21 25 49 25* 16 08 25 1 21 25 49 25* 16 08 49 2 21 25 49 25* 16 08 25* 3 21 25 25* 49 16 08 16 4 16 21 25 25* 49 08 08 5 08 16 21 25 25* 49,算法分析,直接插入排序算法由两重循环组成,对于有n个记录的排序,内循环表明完成一趟排序所需进行的记录关键字间的比较和记录的后移。 若初始时关键字递增有序(正序),这是最好情况。每一趟排序中仅需进行一次关键字的比较,所以总的比较次数
6、为n-1。在while循环之前和之中,至少要移动记录两次,所以总的移动次数为2(n-1)。 若初始时关键字递减有序(反序),这是最坏情况。这时的记录比较和移动次数分别为:,直接插入排序的稳定性,直接插入排序是一种稳定的排序方法。原理:关键字相同的两个对象,在整个排序过程中,不会通过比较而相互交换。,6.3 交换排序,两种常见的交换排序,起泡排序(Bubble Sort) 快速排序(Quick Sort),基本原理:两两比较待排序的对象的关键字,如果发生逆序,则交换之,直到全部对象都排好序为止。,起泡排序的基本过程,假设待排序的n个对象的序列为R0,R1,., Rn-1,起始时排序范围是从R0到
7、Rn-1 在当前的排序范围之内,自右至左对相邻的两个结点依次进行比较,让值较大的结点往下移(下沉),让值较小的结点往上移(上冒)。每趟起泡都能保证值最小的结点上移至最左边,下一遍的排序范围为从下一结点到Rn-1。 在整个排序过程中,最多执行(n-1)遍。但执行的遍数可能少于(n-1),这是因为在执行某一遍的各次比较没有出现结点交换时,就不用进行下一遍的比较。,起泡排序示例,i (0) (1) (2) (3) (4) (5) 21 25 49 25* 16 08 1 08 21 25 49 25* 16 2 08 16 21 25 49 25* 3 08 16 21 25 25* 49 4 08
8、 16 21 25 25* 49,起泡排序算法 BUBBLESORT(rectype R) int i,j,noswap;rectype temp;for (i=0;i=i;j-)if (Rj+1.keyRj.key) tempRj+1;Rj+1=Rj;Rjtemp;noswapFALSE;if (noswap) break; ,起泡排序的时间复杂度,考虑关键字的比较次数和对象移动次数 1、在最好情况下,初始状态是递增有序的,一趟扫描就可完成排序,关键字的比较次数为n-1,没有记录移动。 2、若初始状态是反序的,则需要进行n-1趟扫描,每趟扫描要进行n-i次关键字的比较,且每次需要移动记录三次
9、,因此,最大比较次数和移动次数分别为:,起泡排序方法是稳定的。,最好T(n)=O(n),最坏T(n)=O(n2),平均T(n)=O(n2),6.4 选择排序,两种常见的选择排序,直接选择排序 堆排序,基本原理: 将待排序的结点分为已排序(初始为空)和为未排序两组,依次将未排序的结点中值最小的结点插入已排序的组中。,直接选择排序的基本过程,在一组对象Ri到Rn-1中选择具有最小关键字的对象。 若它不是这组对象中的第一个对象,则将它与这组对象中的第一个对象对调。 删除具有最小关键字的对象(指将最小关键字的对象第一个对象从当前组中去除,即i+),在剩下的对象中重复第(1)、(2)步,直到剩余对象只有
10、一个为止。,直 接 选择 排序 示 例,直接选择排序算法 SELECTSORT(rectype R) int i,j,k;rectype temp;for (i=0;in-1;i+) k=i; /k指向in-1中最小的for (j=i+1;jn;j+)if (Rj.keyRk.key) k=j;if (k!=i) temp=Ri;Ri=Rk;Rk=temp; ,直接选择排序的时间复杂度,2. 当文件为正序时,移动次数为0,文件初态为反序时,每趟排序均要执行交换操作,总的移动次数取最大值3(n-1)。,1、无论初始状态如何,在第i 趟排序中选择最小关键字的记录,需做n-i次比较,因此总的比较次数
11、为:,直接选择排序是不稳定的排序方法。(2,2,1),平均T(n)=O(n2),6.5 归并排序,基本原理,通过对若干个有序结点序列的归并来实现排序。 所谓归并是指将若干个已排好序的部分合并成一个有序的部分。,两路归并的基本思想,设有两个有序表A和B,对象个数分别为al和bl,变量i和j分别是两表的当前指针。设表C是归并后的新有序表,变量k是它的当前指针。i和j对A和B遍历时,依次将关键字小的对象放到C中,当A或B遍历结束时,将另一个表的剩余部分照抄到新表中。,归并算法 MERGE( R, R1:array of integer, low, mid,high:integer) /*Rrow到R
12、mid与Rmid+1到Rhigh是两个有序数组,结果为一个有序数组在R1low到R1high中*/ begini,j,k:integer;i=low; j=mid+1; k=low;while (i=mid) and (j=high) doif (Ri=Rj) then begin R1k=Ri;k:=k+1;I:=I+1;end;else begin R1k=Rj;k:=k+1;j:=j+1;end;while (i=mid) do begin R1k=Ri;k:=k+1;I:=I+1;end;while (j=high) do begin R1k=Rj;k:=k+1;j:=j+1;end;
13、 End;,归并排序就是利用上述归并操作实现排序的。其基本思想是:将待排序列R0到Rn-1看成n个长度为1的有序子序列,把这些子序列两两归并,便得到n/2个有序的子序列。然后再把这n/2个有序的子序列两两归并,如此反复,直到最后得到一个长度为n的有序序列。上述每次的归并操作,都是将两个子序列归并为一个子序列,这就是“二路归并”,类似地还可以有“三路归并”或“多路归并”。,归并过程示例,(25) (57) (48) (37) (12) (92) (86),(25 57) (37 48) (12 92) (86),(25 37 48 57) (12 86 92),(12 25 37 48 57 8
14、6 92),一趟归并算法 MERGEPASS( R, R1:array of integer,length:integer)var i,j:integer; begini=0;while (i+2*length-1n) dobegin MERGE(R,R1,i,i+length-1,i+2*length-1);i=i+2*length;end;if (i+length-1n-1) thenMERGE(R,R1,i,i+length-1,n-1)elsefor j=I to n-1 do R1j=Rj; end,归并排序算法 MERGESORT( R:array of integer) Leng
15、th:integer Beginlength=1; while (lengthn) dobeginMERGEPASS(R,R1,length);length=2*length;MERGEPASS(R1,R,length);length=2*length;end; end,算法复杂性分析,归并排序是稳定的排序方法。,归并排序在第i 趟归并后,有序子文件长度为2i,因此,因此,对于具有n个记录的序列来说,必须做high(log2n)趟归并,每趟归并所花的时间为O(n)。所以,二路归并排序算法的时间复杂度为O(nlog2n),辅助数组所需的空间为O(n)。,6.6 内部排序方法的比较和选择,选取排序方法时需要考虑的因素有:待排序的记录数目记录本身信息量的大小关键字的结构及其分布情况对排序稳定性的要求语言工具的条件、辅助空间的大小,6.7 外部排序简介,如果待排序的记录数很大,无法将所有记录都调入内存,只能将它们存放在外存上,我们称这时的排序为外部排序。外部排序的实现,主要是依靠数据的内外存交换和“内部归并”。,思考题,以单链表为存储结构实现直接插入排序,写出它的算法。 以单链表为存储结构实现直接选择排序,写出它的算法。,