51
数数数数 数数 中中中中中中中中中中中中 中中中中中中中中中中中中 数数数数 数数数数 数数数 数数数 数数数数 数数数数

数据结构 第十章内部排序

Embed Size (px)

DESCRIPTION

数据结构 第十章内部排序. 本章内容 10.1 基本概念 10.2 插入排序 10.3 快速排序 10.4 选择排序 10.5 归并排序 10.6 基数排序. 10.1 基本概念. 关键字 是记录(数据元素)中的一个(或多个)字段。 通常用作检索和排序记录的依据 。 关键字通常可以进行比较操作。. 10.1 基本概念. 排序 : 设含有 n 个记录的文件 {R 1 ,R 2 ,...,R n } ,其相应的关键字为 {K 1 ,K 2 ,...,K n } ,将记录按关键字值非递减 ( 或非递增 ) 顺序排列的过程,称为 排序 。 - PowerPoint PPT Presentation

Citation preview

Page 1: 数据结构 第十章内部排序

《 数据结构》课程

中国科学技术大学网络学院中国科学技术大学网络学院

数据结构数据结构第十章第十章 内部排序内部排序

Page 2: 数据结构 第十章内部排序

本章内容

10.110.1 基本概念基本概念10.210.2 插入排序插入排序10.310.3 快速排序快速排序10.410.4 选择排序选择排序10.510.5 归并排序归并排序10.610.6 基数排序基数排序

Page 3: 数据结构 第十章内部排序

10-3 中国科大《数据结构》

10.1 基本概念

关键字关键字 是记录(数据元素)是记录(数据元素)

中的一个(或多个)中的一个(或多个)字段。字段。通常用作检索通常用作检索和排序记录的依据和排序记录的依据。。

关键字通常可以进行关键字通常可以进行比较操作。比较操作。

Page 4: 数据结构 第十章内部排序

10-4 中国科大《数据结构》

10.1 基本概念

排序排序:设含有设含有 nn 个记录的文件个记录的文件 {R{R11,R,R22,...,R,...,Rnn}} ,其相应的关键字为,其相应的关键字为{K{K11,K,K22,...,K,...,Knn}} ,将记录按关键字值非递减,将记录按关键字值非递减 (( 或非递增或非递增 )) 顺序排列的顺序排列的过程,称为过程,称为排序。。

排序的稳定性排序的稳定性:对所有的:对所有的 KKii=K=Kjj (i≠j), (i≠j), 若排序前若排序前 RRii 领先于领先于 RRjj,, 排序后排序后RRii 仍领先于仍领先于 RRjj,, 则称该排序方法是则称该排序方法是稳定的,反之,称为,反之,称为不稳定的。的。稳定性是对序列中的两个相同的关键字在初始序列和最终有序序列稳定性是对序列中的两个相同的关键字在初始序列和最终有序序列中相对位置(即领先关系)是否变化。中相对位置(即领先关系)是否变化。

排序分类排序分类 内部排序内部排序:待排序文件的全部记录存放在内存进行的排序,称:待排序文件的全部记录存放在内存进行的排序,称

为内部排序。为内部排序。 外部排序外部排序:排序过程中需要进行内外存数据交换的排序,称为:排序过程中需要进行内外存数据交换的排序,称为

外部排序。外部排序。

Page 5: 数据结构 第十章内部排序

10-5 中国科大《数据结构》

10.1 基本概念

内排序分类:内排序分类: 按排序过程依据的原则分为:按排序过程依据的原则分为:

插入排序插入排序交换排序交换排序选择排序选择排序归并排序归并排序计数排序计数排序

按排序过程所需的工作量分:按排序过程所需的工作量分:简单排序简单排序先进排序先进排序基数排序基数排序

Page 6: 数据结构 第十章内部排序

10-6 中国科大《数据结构》

10.2 插入排序

10.2.1 10.2.1 直接插入排序直接插入排序它是最简单的排序方法它是最简单的排序方法

基本思想:依次将每个待排序的记录插入到一个有序子文件的合适基本思想:依次将每个待排序的记录插入到一个有序子文件的合适位置位置 (( 有序子文件记录数增有序子文件记录数增 1)1)

例如:已有待排序文件为:例如:已有待排序文件为: 45,34,78,12,34,32,29,6445,34,78,12,34,32,29,64 。首先将文件。首先将文件的第一个记录,视为有序文件,然后从第二个记录开始,直到最后的第一个记录,视为有序文件,然后从第二个记录开始,直到最后一个记录,依次将他们插入到有序文件的合适位置。一个记录,依次将他们插入到有序文件的合适位置。

12 34’ 32 29 6445 34 78

Page 7: 数据结构 第十章内部排序

10-7 中国科大《数据结构》

10.2 插入排序

直接插入排序算法直接插入排序算法

说明:监视哨说明:监视哨 L.r[0] 的作用:的作用: 保存记录保存记录 L.r[i]L.r[i] 的副本;的副本; 监视下标监视下标 jj 是否越界,自动控制循环结束是否越界,自动控制循环结束

void InsertSort( SqList &L ) {

int i, j;

for( i=2; i<=L.length; ++i )

if (L.r[i].key < L.r[i-1].key) // "<", 需将 L.r[i] 插入有序子表 { L.r[0]=L.r[i]; // 复制为哨兵 for(j=i-1; L.r[0].key<L.r[j].key; --j )

L.r[j+1]=L.r[j]; // 记录后移 L.r[j+1]=L.r[0]; // 插入到正确位置 }

}

Page 8: 数据结构 第十章内部排序

10-8 中国科大《数据结构》

10.2 插入排序

算法分析算法分析直接插入排序的算法简洁,容易实现。从时间来看,排序的基本操直接插入排序的算法简洁,容易实现。从时间来看,排序的基本操作为:比较两个记录的大小和移动记录。其中:作为:比较两个记录的大小和移动记录。其中:

最小比较次数:最小比较次数: Cmin = n-1 = O(n)Cmin = n-1 = O(n)

最大比较次数:最大比较次数: Cmax =(2+3+…+n)=(n+2)(n-1)/2 = O(nCmax =(2+3+…+n)=(n+2)(n-1)/2 = O(n2 2 ))

最小移动次数:最小移动次数: Mmin = 0Mmin = 0

最大移动次数:最大移动次数: Mmax = (2+1 + 3+1 + … + n+1) = O(nMmax = (2+1 + 3+1 + … + n+1) = O(n22))

若待排序记录序列中出现各种可能排列的概率相同,则可取上述最若待排序记录序列中出现各种可能排列的概率相同,则可取上述最好情况和最坏情况的平均情况。在平均情况下的关键字比较次数和好情况和最坏情况的平均情况。在平均情况下的关键字比较次数和记录移动次数约为 记录移动次数约为 nn22/4/4 。因此,直接插入排序的时间复杂度为 。因此,直接插入排序的时间复杂度为 oo(n(n22)) 。。

Page 9: 数据结构 第十章内部排序

10-9 中国科大《数据结构》

10.2 插入排序

结论结论1.1. 直接插入排序的效率与待排文件的关键字排列有关;直接插入排序的效率与待排文件的关键字排列有关;

2.2. 直接插入排序的时间复杂度为直接插入排序的时间复杂度为 O(nO(n22)) ;;3.3. 直接插入排序是稳定的直接插入排序是稳定的 (( 这一点由过程中这一点由过程中 WHILEWHILE 语句的条件语句的条件

“<”保证的“<”保证的 )) 。 。

Page 10: 数据结构 第十章内部排序

10-10 中国科大《数据结构》

10.2 插入排序

10.2.210.2.2 折半插入排序折半插入排序 (Binary Insertsort)(Binary Insertsort)

由于是在有序子文件中确定插入的位置,因此可用折半查由于是在有序子文件中确定插入的位置,因此可用折半查找来代替直接插入排序法中的顺序查找,从而可减少比较次数。找来代替直接插入排序法中的顺序查找,从而可减少比较次数。

基本思想基本思想 设在顺序表中有一个记录序列 设在顺序表中有一个记录序列 R[1], R[2], …, R[R[1], R[2], …, R[nn]] 。其中,。其中, RR

[1], R[2], …, R[[1], R[2], …, R[ii-1]-1] 是已经排好序的记录。是已经排好序的记录。 在插入 在插入 R[i]R[i] 时,利用时,利用折半搜索法折半搜索法寻找 寻找 R[i]R[i] 的插入位置。的插入位置。

Page 11: 数据结构 第十章内部排序

10-11 中国科大《数据结构》

10.2 插入排序

折半插入排序算法折半插入排序算法

void BInsertSort(SqList &L) { int i, j, m, low, high; 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 ){ // 在 r[low..high] 中折半查找有序插入的位置 m = (low+high)/2; // 折半 if ( L.r[0].key < L.r[m].key ) high = m-1; // 插入点在低半区 else low = m+1; // 插入点在高半区 } for( j=i-1; j>=high+1; --j ) L.r[j+1]=L.r[j]; // 记录后移 L.r[high+1]=L.r[0]; // 插入 } }

Page 12: 数据结构 第十章内部排序

10-12 中国科大《数据结构》

10.2 插入排序

算法分析算法分析 折半插入排序所需要的关键字比较次数与待排序记录序列的初折半插入排序所需要的关键字比较次数与待排序记录序列的初

始排列无关,仅依赖于记录个数。在插入第 始排列无关,仅依赖于记录个数。在插入第 i i 个记录时,需要个记录时,需要经过 经过 loglog22ii +1 +1 次关键字比较,才能确定它应插入的位置。将 次关键字比较,才能确定它应插入的位置。将 nn 个记录用折半插入排序所进行的关键字比较次数为个记录用折半插入排序所进行的关键字比较次数为 O(nlogO(nlog22n)n) ..

折半插入排序的时间复杂度仍为折半插入排序的时间复杂度仍为 O(nO(n22)) 当 当 nn 较大时,总的关键字比较次数比直接插入排序的最坏情况较大时,总的关键字比较次数比直接插入排序的最坏情况

要好得多,但比其最好情况要差。要好得多,但比其最好情况要差。 当初始排列已经按关键字排好序或接近有序时,直接插入排序当初始排列已经按关键字排好序或接近有序时,直接插入排序

比折半插入排序执行的关键字比较次数要少。折半插入排序的比折半插入排序执行的关键字比较次数要少。折半插入排序的记录移动次数与直接插入排序相同,依赖于记录的初始排列。记录移动次数与直接插入排序相同,依赖于记录的初始排列。

折半插入排序是一个稳定的排序方法。折半插入排序是一个稳定的排序方法。

Page 13: 数据结构 第十章内部排序

10-13 中国科大《数据结构》

10.2 插入排序

10.2.3 10.2.3 ShellShell 排序排序 基本思想:希尔排序(基本思想:希尔排序( Shell`s MethoolShell`s Methool )又称为缩小增量排序,)又称为缩小增量排序,也是一种插入排序方法。它将待排序数据文件分割成若干个较小的也是一种插入排序方法。它将待排序数据文件分割成若干个较小的子文件,对各个子文件分别进行直接插入排序,当文件达到基本有子文件,对各个子文件分别进行直接插入排序,当文件达到基本有序时,再对整个文件进行一次直接插入排序。序时,再对整个文件进行一次直接插入排序。

适用条件适用条件如果待排序文件如果待排序文件 "" 基本有序基本有序 "" ,即文件中具有特性:,即文件中具有特性:

r[i].key < Max {r[j ].key} 1≤j 1≤j << II

的记录数的记录数较少较少 ,则文件中大多数记录不需要进行插入, 因而排序 ,则文件中大多数记录不需要进行插入, 因而排序效率可以提高,接近于效率可以提高,接近于 O(n)O(n) 。。

Page 14: 数据结构 第十章内部排序

10-14 中国科大《数据结构》

10.2 插入排序

例例 11 :设初始关键字为::设初始关键字为: 第一趟以步长为第一趟以步长为 55 分割为分割为 55 个子文件:个子文件:{{R1,R6} {} {R2,R7} {} {R3,R8} { } { R4,R6} {} {R5,R10} }

对每个子文件进行直接插入排序对每个子文件进行直接插入排序 第二趟以步长为第二趟以步长为 33 对第一趟排序结果对第一趟排序结果

分割为分割为 3 3 个子文件:个子文件:{R{R11,R,R44,R,R77,R,R1010} {R} {R22,R,R55,R,R88} {(R} {(R33,R,R66,R,R99}}

对每个子文件进行直接插入排序对每个子文件进行直接插入排序第三趟以步长为第三趟以步长为 11 对第二趟排序结果进行对第二趟排序结果进行

直接插入排序直接插入排序

49 38 65 97 76 13 27 49' 55 04

13 27 49' 55 04 49 38 65 97 76

原始数据 :

第一趟排序 :

第二趟排序 : 49' 49 9713 38 55 55 7604 27 65

04 13 27 38 38 49' 49 55 55 65 76 76 97第三趟排序 :

Page 15: 数据结构 第十章内部排序

10-15 中国科大《数据结构》

10.2 插入排序

例例 22 :对下列数据进行:对下列数据进行 shellshell 排序,步长分别选为排序,步长分别选为 44 、、 22 、、 11 。。

12 34’ 32 29 6445 34 78

Page 16: 数据结构 第十章内部排序

10-16 中国科大《数据结构》

10.2 插入排序

希尔排序算法希尔排序算法

void ShellInsert( SqList &L,int dk ){ for( i=dk+1; i<=L.Length; i++ ) if(L.r[i].key < L.r[i-dk].key){ // 需将 L.r[i] 插入有序增量子表

L.r[0] = L.r[i]; // 暂存在 L.r[0],但不是哨兵。for(j=i-dk; j>0 && L.r[0].key<L.r[j].key; j-=dk)

L.r[j+dk] = L.r[j]; // 记录后移,查找插入位置L.r[j+dk] = L.r[0];

}} void ShellSort(SqList &L, int dlta[], int t){ // 按增量序列 dlta[0..t-1] 对顺序表 L 作希尔排序 for(k=0; k<t; t++){ ShellInsert( L, dlta[k] ); // 一趟增量为 dlta[k] 的插入排序 } 

Page 17: 数据结构 第十章内部排序

10-17 中国科大《数据结构》

10.2 插入排序

增量的取法增量的取法最初 最初 shellshell 提出取 提出取 dd11 = = n/2n/2 ,, dd22 = = dd11/2/2 ,直到,直到 ddtt = 1 = 1 。后来 。后来

knuthknuth 提出取提出取 ddi+1i+1 = = ddii/3/3 +1 +1 。还有人提出都取奇数为好,也有人提出各。还有人提出都取奇数为好,也有人提出各增量互质为好。增量互质为好。

算法分析算法分析 不稳定不稳定 空间代价:空间代价: O(1)O(1)

增量每次除以增量每次除以 22 递减,时间代价:递减,时间代价: O(nO(n22))

选择适当的增量序列,可以使得时间代价接近选择适当的增量序列,可以使得时间代价接近 O(n)O(n)

增量每次除以增量每次除以 22 递减递减””时,效率仍然为时,效率仍然为 OO(n(n22))

问题:选取的增量之间并不互质问题:选取的增量之间并不互质 间距为间距为 22k-1k-1 的子序列都是由那些间距为的子序列都是由那些间距为 22kk 的子序列组成的的子序列组成的 上一轮循环中这些子序列都已经排过序了,导致处理效率不高上一轮循环中这些子序列都已经排过序了,导致处理效率不高

Page 18: 数据结构 第十章内部排序

10-18 中国科大《数据结构》

10.3 交换排序

10.3.1 10.3.1 冒泡排序冒泡排序冒泡排序是一种简单而且容易理解的排序方法,它和气泡冒泡排序是一种简单而且容易理解的排序方法,它和气泡

从水中不断往上冒的情况有些类似。从水中不断往上冒的情况有些类似。 其基本思想其基本思想

对存放原始数据的数组,按从后往前的方向进行多次扫描,对存放原始数据的数组,按从后往前的方向进行多次扫描,每次扫描称为一趟 每次扫描称为一趟 (pass)(pass) 。当发现相邻两个数据的次序与排序要。当发现相邻两个数据的次序与排序要求的“递增次序”不符合时,就互换两个数据。这样,较小的数据求的“递增次序”不符合时,就互换两个数据。这样,较小的数据就会逐单元向前移动,好象气泡向上浮起一样。就会逐单元向前移动,好象气泡向上浮起一样。

示例示例

12 34’ 32 29 64783445

Page 19: 数据结构 第十章内部排序

10-19 中国科大《数据结构》

10.3 交换排序

冒泡排序算法冒泡排序算法

void BubbleSort( SqList &L ){ // 从下往上扫描的起泡排序

for( i=0; i<n-2;i++ ){ // 做 n-1趟排序

noSwap=TRUE; // 置未交换标志

for( j=n-1;j>=i;j-- ) // 从下往上扫描 if(L.r[j+1].key < L.r[j].key)

{ temp=L.r[j+1]; // 交换记录 L.r[j+1]=L.r[j];

L.r[j]=temp;

noSwap=FALSE;

}

if( noSwap ) break; // 本趟扫描未发生交换,则终止算法 }

}

Page 20: 数据结构 第十章内部排序

10-20 中国科大《数据结构》

10.3 交换排序

算法评价算法评价 算法稳定算法稳定 空间代价:空间代价: O(1) O(1)

时间代价 :时间代价 :比较次数 :比较次数 :

交换次数最多为交换次数最多为 O(nO(n22)) ,最少为,最少为 00 ,平均为,平均为 O(nO(n22)) 。。最大,平均时间代价均为最大,平均时间代价均为 O(nO(n22)) 。。最小时间代价为最小时间代价为 O(n)O(n) :最佳情况下只运行第一轮循环:最佳情况下只运行第一轮循环

Page 21: 数据结构 第十章内部排序

10-21 中国科大《数据结构》

10.3 交换排序

10.3.2 10.3.2 快速排序快速排序 基本思想基本思想

任取某个记录作为基准(通常选文件的第一个记录),将所有任取某个记录作为基准(通常选文件的第一个记录),将所有关键字不大于它的记录放在它的前面,将所有关键字不小于它关键字不大于它的记录放在它的前面,将所有关键字不小于它的记录放在它的后面;的记录放在它的后面;

这样遍历一趟文件后,将文件以该记录为界分为两部分;这样遍历一趟文件后,将文件以该记录为界分为两部分; 然后对各部分重复上述过程,直到每一部分仅剩一个记录为止。然后对各部分重复上述过程,直到每一部分仅剩一个记录为止。

特点:基于分治法的排序:快速、归并。分治策略的实例特点:基于分治法的排序:快速、归并。分治策略的实例 BSTBST 查找、插入、删除算法查找、插入、删除算法 快速排序、归并排序快速排序、归并排序 二分检索二分检索

主要思想:划分、求解子问题主要思想:划分、求解子问题 (( 子问题不重叠子问题不重叠 )) 、综合解、综合解

Page 22: 数据结构 第十章内部排序

10-22 中国科大《数据结构》

10.3 交换排序

25 34 45 32 34’12 29 64

25 29 12

29 34’34 45

32

64

25

34

12 25

12

34’64 45 34

34’最终排序结果: 12 25 29 32 34’ 34 45 64

45

Page 23: 数据结构 第十章内部排序

10-23 中国科大《数据结构》

10.3 交换排序

快速排序算法评价快速排序算法评价 快速排序算法不稳定。快速排序算法不稳定。 常用“三者取中”法来选取划分记录,即取首记录常用“三者取中”法来选取划分记录,即取首记录 r[s].key.r[s].key. 尾记录尾记录 r[t].keyr[t].key 和和

中间记录中间记录 r[(s+t)/2].keyr[(s+t)/2].key 三者的中间值为划分记录。三者的中间值为划分记录。 算法分析算法分析

最差情况:最差情况: 时间代价: 时间代价: O(nO(n22) )

空间代价: 空间代价: O(n) O(n)

最佳情况:最佳情况: 时间代价:时间代价: O(nlog n) O(nlog n)

空间代价:空间代价: O(log n) O(log n)

平均情况:平均情况: 时间代价:时间代价: O(nlog n) O(nlog n)

空间代价:空间代价: O(log n) O(log n)

Page 24: 数据结构 第十章内部排序

10-24 中国科大《数据结构》

10.4 选择排序

基本思想基本思想每一趟 每一趟 (( 例如第 例如第 ii 趟,趟, i i = 1, 2, …, = 1, 2, …, nn-1-1) ) 在后面 在后面

n-i+1n-i+1 个待排序记录中选出关键字最小的记录个待排序记录中选出关键字最小的记录 , , 作为有作为有序记录序列的第 序记录序列的第 ii 个记录。待到第个记录。待到第 n-1n-1 趟作完,待排趟作完,待排序记录只剩下序记录只剩下 11个,就不用再选了。个,就不用再选了。

Page 25: 数据结构 第十章内部排序

10-25 中国科大《数据结构》

10.4 选择排序

10.4.1 10.4.1 简单选择排序简单选择排序 基本思想基本思想

首先在所有记录中选出关键字最小的记录,把它与第首先在所有记录中选出关键字最小的记录,把它与第 11 个个记录交换,然后在其余的记录中再选出关键字次最小的记录与第记录交换,然后在其余的记录中再选出关键字次最小的记录与第 22

个记录交换,以次类推……,直到所有记录排序完成。个记录交换,以次类推……,直到所有记录排序完成。

Page 26: 数据结构 第十章内部排序

10-26 中国科大《数据结构》

10.4 选择排序

初始关键字序列初始关键字序列34 12 49 28 31 52 51 49*

1 2 3 4 5 6 7 80

i=112 34 49 28 31 52 51 49*

i=212 28 49 34 31 52 51 49*

i=312 28 31 34 49 52 51 49*

i=412 28 31 34 49 52 51 49*

i=512 28 31 34 49 52 51 49*

i=612 28 31 34 49 49* 51 52

i=712 28 31 34 49 49* 51 52

Page 27: 数据结构 第十章内部排序

10-27 中国科大《数据结构》

10.4 选择排序

简单选择排序的算法简单选择排序的算法

void SelectSort(SqList &L){ int i, j; RedType temp; for( i=0; i<L.length-1; i++ ){ // 做 n-1趟选择排序 k = i; // 在当前无序区选关键字最小的记录 for( j=i+1; j<L.length; j++ ) if( L.r[j].key < L.r[k].key ) k = j ; if( k != i ){ temp = L.r[i]; L.r[i] = L.r[k]; L.r[k] =temp; } } }

Page 28: 数据结构 第十章内部排序

10-28 中国科大《数据结构》

10.4 选择排序

算法分析算法分析 交换次数:正序时交换次数最少,为交换次数:正序时交换次数最少,为 00 次,逆序时最多,为次,逆序时最多,为 n-1n-1

次。次。 比较次数:与初始文件关键字排列无关,为比较次数:与初始文件关键字排列无关,为 n(n-1)/2n(n-1)/2 次。次。 简单选择排序时间复杂度为简单选择排序时间复杂度为 O(nO(n22)) ,并且是稳定的排序。,并且是稳定的排序。

Page 29: 数据结构 第十章内部排序

10-29 中国科大《数据结构》

10.4 选择排序

10.4.2 10.4.2 堆排序堆排序 堆的定义

对于 n 个元素的序列 {k1,

k2,...,kn} ,当且仅当满足以下关系时,称之为堆。

96

83

38 11

27

9

(a) 大顶堆 (max heap) (b) 小顶堆 (min heap)

12

36

85 47

24

30 53

91

9696 8383 2727 3838 1111 99 1212 3636 2424 8585 4747 3030 5353 9191

Page 30: 数据结构 第十章内部排序

10-30 中国科大《数据结构》

10.4 选择排序

若将堆视为一个完全二叉树,则堆的含义为:完全二叉树中所有非若将堆视为一个完全二叉树,则堆的含义为:完全二叉树中所有非叶结点的值叶结点的值 (r(rii) ) 均不大于均不大于 (( 或不小于或不小于 )) 其左孩子的值其左孩子的值 (r(r2i2i))、右孩子、右孩子的值的值 (r(r2i+12i+1) ) 。。

堆顶元素堆顶元素 ((完全二叉树的根完全二叉树的根 )) 是序列中最小是序列中最小 (( 或最大或最大 )) 的元素。的元素。12

65

4981 55

34 98

是堆

14

36

40

73

27

Page 31: 数据结构 第十章内部排序

10-31 中国科大《数据结构》

10.4 选择排序

堆排序堆排序 (Heap Sort)(Heap Sort) 基本思想基本思想1.1. 以初始关键字序列,建立堆; 以初始关键字序列,建立堆; 2.2. 输出堆顶最小元素;输出堆顶最小元素;3.3. 调整余下的元素,使其成为一个新堆;调整余下的元素,使其成为一个新堆;4.4. 重复重复 2,32,3 步,直到步,直到 nn 个元素输出,得到 一个有序序列。个元素输出,得到 一个有序序列。

关键问题:关键问题: 要解决要解决 11 和和 33 ,即如何由一个无序序列建成一个堆,即如何由一个无序序列建成一个堆 ? ?

如何调整余下的元素成为一个新堆如何调整余下的元素成为一个新堆 ? ?

Page 32: 数据结构 第十章内部排序

10-32 中国科大《数据结构》

10.4 选择排序

调整方法调整方法1.1. 将堆顶元素和堆的最后一个元素位置交换;将堆顶元素和堆的最后一个元素位置交换;2.2. 然后以当前堆顶元素和其左、右子树的根结点进行比较然后以当前堆顶元素和其左、右子树的根结点进行比较 (( 此时,此时,左、右子树均为堆左、右子树均为堆 )) ,并与值较小的结点进行交换;,并与值较小的结点进行交换;

3.3. 重复第重复第 22 步,继续调整被交换过的子树,直到叶结点或没进行步,继续调整被交换过的子树,直到叶结点或没进行交换为止。交换为止。

称这个调整过程为称这个调整过程为 ""筛选筛选 "" 。。

Page 33: 数据结构 第十章内部排序

10-33 中国科大《数据结构》

10.4 选择排序

例如:设有关键字例如:设有关键字 {13,38,27,49’,76,65,49,97}{13,38,27,49’,76,65,49,97} ,按初始次序构成一,按初始次序构成一棵完全二叉树,形成一个堆如下图:棵完全二叉树,形成一个堆如下图:

13

76

38

49‘

97

65 49

输出输出 1133

27

筛选筛选 97

76

38

49’

13

65 49

27 49

27

38

49‘

13

65 97

筛选结果筛选结果 输出输出 2727

76

97

76

38

49’

13

65 27

491

2

338

76

49‘

97

13

65 27

49

1

2

3

Page 34: 数据结构 第十章内部排序

10-34 中国科大《数据结构》

10.4 选择排序

筛选过程筛选过程

void HeapAdjust (SqList R[], int s, int m) {

// 已知 R[s..m] 中记录的关键字除 R[s].key 之外均满足堆的定义,本函数调整 //R[s] 的关键字,使 R[s..m]成为一个大顶堆(对其中记录的关键字而言) rc = R[s];

for ( j=2*s; j<=m; j*=2 ) {

// 沿 key 较大的孩子结点向下筛选 if ( j<m && R[j].key<R[j+1].key ) ++j; // j 为 key 较大的记录的下标 if ( rc.key >= R[j].key ) break; // rc 应插入在位置 s 上 R[s] = R[j]; s = j;

}

R[s] = rc; // 插入} // HeapAdjust

Page 35: 数据结构 第十章内部排序

10-35 中国科大《数据结构》

10.4 选择排序

无序序列建堆过程无序序列建堆过程方法:从完全二叉树的最后一个非叶结点 方法:从完全二叉树的最后一个非叶结点 n/2 n/2 开始,反复调用开始,反复调用筛选过程,直到第一个结点,则得到一个堆。筛选过程,直到第一个结点,则得到一个堆。

例:例: {{4949 ,, 3838 ,, 6565 ,, 97 ,, 7676 ,, 1313 ,, 2727 ,, 49’}49’}

49

76

38

97

49’

13 27

65

49

76

38

49‘

97

65 27

13

13

76

38

49‘

97

65 49

27

Page 36: 数据结构 第十章内部排序

10-36 中国科大《数据结构》

10.4 选择排序

堆排序的算法堆排序的算法

void HeapSort ( SqList R[], int n ) { // 对记录序列 R[1..n] 进行堆排序。

for ( i=n/2; i>0; --i ) // 把 R[1..n]建成大顶堆

HeapAdjust ( R, i, n );

for ( i=n; i>1; --i ) {

R[1]←→R[i]; // 将堆顶记录和当前未经排序子序列 R[1..i] 中最后一个记录相互交换

HeapAdjust(R, 1, i-1); } // 将 R[1..i-1] 重新调整为大顶堆

} // HeapSort

Page 37: 数据结构 第十章内部排序

10-37 中国科大《数据结构》

10.4 选择排序

堆排序的时间复杂度分析堆排序的时间复杂度分析1.1. 对深度为对深度为 kk 的堆,“筛选”所需进行的关键字比较的次数至多的堆,“筛选”所需进行的关键字比较的次数至多

为为 2(k-1);2(k-1);

2.2. 对对 nn 个关键字,建成深度为个关键字,建成深度为 h(=h(=log2nlog2n+1)+1) 的堆,所需进行的的堆,所需进行的关键字比较的次数至多为关键字比较的次数至多为 4n;4n;

3.3. 调整“堆顶”调整“堆顶” n-1n-1 次,总共进行的关键字比较的次数不超过次,总共进行的关键字比较的次数不超过 2( 2(

log2(n-1)log2(n-1) + + log2(n-2)log2(n-2)+ …+log22)<2n( + …+log22)<2n( log2nlog2n ) )

因此,堆排序的时间复杂度为因此,堆排序的时间复杂度为 O(O(nnloglognn)) ,且不稳定。,且不稳定。

Page 38: 数据结构 第十章内部排序

10-38 中国科大《数据结构》

10.5 归并排序

归并归并归并是指将若干个已排序好的有序表合并成一个有序表。归并是指将若干个已排序好的有序表合并成一个有序表。

两个有序表的归并称为二路归并。 两个有序表的归并称为二路归并。 归并排序归并排序

将待排序的将待排序的 nn 个记录,看作个记录,看作 nn 个有序的子序列,每个子序个有序的子序列,每个子序列的长度为列的长度为 11 。然后两两归并,得到。然后两两归并,得到 n/2n/2 个长度为个长度为 22 或为或为 11 的子序的子序列;再两两归并,列;再两两归并, ...... ,如此重复,直到得到长度为,如此重复,直到得到长度为 nn 的子序列为的子序列为止。这种排序的方法称为止。这种排序的方法称为 2_2_ 路归并排序。路归并排序。

Page 39: 数据结构 第十章内部排序

10-39 中国科大《数据结构》

10.5 归并排序

2_路归并排序的核心操作:将一维数组中前后两个有序序列归并为一个有序序列。

例: 将一维数组 49,38,65,97,76,13,27,49 进行 2_路归并排序:

初始:  [49] , [38] , [65] , [97] , [76] , [13] , [27] ,[49]

第一趟: [38 , 49] , [65 , 97] , [13 , 76] , [27 , 49]

第二趟: [38 , 49 , 65 , 97] , [13 , 27 , 49 , 76]

第三趟: [13 , 27 , 38 , 49 , 49 , 65 , 76 , 97]

Page 40: 数据结构 第十章内部排序

10-40 中国科大《数据结构》

10.5 归并排序

将两个有序序列归并为一个有序序列的算法

void merge (Sqlist SR,Sqlist &TR,int i,int m, int n)

// 将有序表 SR.r[i..m] 以及 SR.r[m+1..n] 有序归并到 TR.r[i..n] 中

{ la=i;lb=m+1;lc=i; // 序列 la,lb,lc 的始点

while(la<=m &&lb<=n)

{ if LT(SR.r[la].key, SR.r[lb].key) TR.r[lc++]=SR.r[la++] // 有序合并

else TR.r[lc++]=SR.r[lb++]

}

if ( la<=m) TR.r[lc..n]=SR.r[la..m]; //剩余复制

if ( lb<=n) TR.r[lc..n]=SR.r[lb..n];

}

Page 41: 数据结构 第十章内部排序

10-41 中国科大《数据结构》

10.5 归并排序

一趟归并排序操作需调用 n/(2h) 次算法 merge ,将 SR[1..n] 前后相邻且长度为 h

的有序段两两归并 , 得到前后眼相邻、长度为 2h 的有序段 , 并放在 TR[1..n] 中。整个归并排序需要 [log2n]趟。

递归算法:排序区间: R[s..t]

设: m= ( int ) ((low+high)/2)

可递归地对两个子区间 R[s..m] 和 R[m+1..t] 进行归并排序。然后将两个已排序子区间合并为一个有序区间。

void MSort(SeqList SR,SeqList TR, ints,int t)// 将有序表 SR.r[s..t] 有序归并排序到 TR.r[s..t] 中{ if (s==t) TR.r[s]=SR.r[s]; else { m=(s+t)/2; MSort( SR,MR,s,m); MSort( SR,MR,m+1,t); merge(MR,TR,s,m,t) } }

Page 42: 数据结构 第十章内部排序

10-42 中国科大《数据结构》

10.5 归并排序

算法分析 每趟归并的时间复杂度为 O(n),

整个算法需㏒ 2n趟。时间复杂度为 O(nlog2n) 。 归并排序算法虽简单,但占用辅助空间大,实用性差。

Page 43: 数据结构 第十章内部排序

10-43 中国科大《数据结构》

10.6 基数排序

基数排序基数排序是一种无需进行关键字比较的新排序方法,其基本操作是是一种无需进行关键字比较的新排序方法,其基本操作是

“分配”和“收集”。“分配”和“收集”。 基数排序原理基数排序原理

基数排序是按组成关键字的各位的值进行分配和收集,与基数排序是按组成关键字的各位的值进行分配和收集,与前面介绍的排序方法不同,它无需进行关键字之间的比较。前面介绍的排序方法不同,它无需进行关键字之间的比较。

设关键字有设关键字有 d d 位,每位的取值范围为 位,每位的取值范围为 r (r ( 称为基数称为基数 )) ,则,则需要进行需要进行 d d 趟分配与收集,需要设立 趟分配与收集,需要设立 r r 个队列。例如,若每位是个队列。例如,若每位是十进制数字,则需要设立十进制数字,则需要设立 1010 个队列,若每位由小写字母组成,则个队列,若每位由小写字母组成,则要设立要设立 2626 个队列 。个队列 。

Page 44: 数据结构 第十章内部排序

10-44 中国科大《数据结构》

10.6 基数排序

基数排序的步骤基数排序的步骤1.1. 从关键字的低位开始进行第从关键字的低位开始进行第 ii趟趟 (i=1,2,...d)(i=1,2,...d) 分配即将单链表中分配即将单链表中

的记录依次按关键字的第的记录依次按关键字的第 ii 位分配到相应编号的队列中;位分配到相应编号的队列中;2.2. 分配完毕后,将各队列的记录按队列编号顺序收集成一个单链分配完毕后,将各队列的记录按队列编号顺序收集成一个单链

表;表;3.3. 上一趟形成的链队,作为下一趟的输入,重复⑴⑵,直到第上一趟形成的链队,作为下一趟的输入,重复⑴⑵,直到第 dd

趟收集完毕,所得单链表已成为有序表。趟收集完毕,所得单链表已成为有序表。

Page 45: 数据结构 第十章内部排序

10-45 中国科大《数据结构》

10.6 基数排序

例:例:初始 初始 278—109—063—930—589—184—505—269—008—083278—109—063—930—589—184—505—269—008—083

0 1 2 3 4 5 6 7 8 90 1 2 3 4 5 6 7 8 9

第一趟分配 第一趟分配

278 109063930

589

184 505

269008083

第二趟分配第二趟分配 109 589109 589 008 269 184008 269 184 505 930 063 278 083505 930 063 278 083第二趟收集 第二趟收集 505—008—109—930—063—269—278—083—184—589505—008—109—930—063—269—278—083—184—589第三趟分配 第三趟分配 083 083 063 184 278 589063 184 278 589 008 109 269 505 930008 109 269 505 930 第三趟收集第三趟收集 008—063—083—109—184—269—278—505—589—930008—063—083—109—184—269—278—505—589—930

第一趟收集第一趟收集 930—063—083—184—505—278—008—109—589—269930—063—083—184—505—278—008—109—589—269

Page 46: 数据结构 第十章内部排序

10-46 中国科大《数据结构》

10.6 基数排序

基数排序的特点基数排序的特点1.1. 基数排序的基本操作是基数排序的基本操作是 ""分配分配 ""和和 "" 收集收集 "",而不是关键字之,而不是关键字之

间的比较;间的比较;2.2. 基数排序是稳定的,其时间复杂度为基数排序是稳定的,其时间复杂度为 O(d(n+rd))O(d(n+rd)) ,其中,其中 nn 是是

记录数,记录数, dd 是关键字的位数,是关键字的位数, rr 是关键字各位的值域;是关键字各位的值域;3.3. 基数排序要进行基数排序要进行 dd 趟分配和收集趟分配和收集 ,,需需 rr 个队列。个队列。

Page 47: 数据结构 第十章内部排序

10-47 中国科大《数据结构》

10.7 各种内部排序方法的比较

排序方法选择主要考虑:排序方法选择主要考虑: 待排序记录个数待排序记录个数 nn 记录本身的大小记录本身的大小 关键字的分布情况关键字的分布情况 对排序稳定性要求对排序稳定性要求

Page 48: 数据结构 第十章内部排序

10-48 中国科大《数据结构》

10.7 各种内部排序方法的比较

时间特性:时间特性: 时间复杂度为时间复杂度为 O(nlogn):O(nlogn): 快速、堆、归并排序快速、堆、归并排序快速最快,在快速最快,在 nn 较大时,归并较堆更快较大时,归并较堆更快 时间复杂度为时间复杂度为 O(nO(n22):): 插入、冒泡、选择排序插入、冒泡、选择排序插入最常用,尤其基本有序时,选择记录移动次数最少插入最常用,尤其基本有序时,选择记录移动次数最少 时间复杂度为时间复杂度为 O(n):O(n): 基数排序基数排序 当待排序记录有序时:插入和冒泡可达到当待排序记录有序时:插入和冒泡可达到 O(n)O(n) ,快速蜕化到,快速蜕化到 OO

(n(n22)) ;; 选择、堆和归并排序的时间特性不随关键字分布而改变选择、堆和归并排序的时间特性不随关键字分布而改变

Page 49: 数据结构 第十章内部排序

10-49 中国科大《数据结构》

10.7 各种内部排序方法的比较

空间特性:空间特性: 所有的简单排序和堆排序的空间复杂度均为所有的简单排序和堆排序的空间复杂度均为 O(1)O(1) ;; 快速排序为快速排序为 O(logn);O(logn); 归并排序和基数排序所需辅助空间最多,其空间复杂度为归并排序和基数排序所需辅助空间最多,其空间复杂度为 O(n).O(n).

稳定性:稳定性: 快速排序、希尔排序和堆排序是不稳定的快速排序、希尔排序和堆排序是不稳定的 ;; 其他排序方法都是稳定的其他排序方法都是稳定的

Page 50: 数据结构 第十章内部排序

10-50 中国科大《数据结构》

10.7 各种内部排序方法的比较

排序方法比较排序方法比较

排序方法 平均时间 最坏情况 最好情况 辅助空间 稳定性

插入排序 O(n2) O(n2) O(n) O(1) √

选择排序 O(n2) O(n2) O(n2) O(1) √

冒泡排序 O(n2) O(n2) O(n) O(1) √

快速排序 O(nlogn) O(n2) O(nlogn) O(nlogn) ×

归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) √

堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) ×

基数排序 O(d*n) O(d*n) O(d*n) O(n) √

Page 51: 数据结构 第十章内部排序

10-51 中国科大《数据结构》

习题

本章习题参见教师网页:本章习题参见教师网页:http://staff.ustc.edu.cn/~leeyihttp://staff.ustc.edu.cn/~leeyi