c数据结构chapt10
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
各 趟 排 序 结 果 i=1
21 0
25 1
49 2
25* 3
16
41
49 2
25* 3
16 4
08 5
25 temp
i=2
21 25 49 25* 16 49 08
0
1
2
3
4
5
temp
i=3
21 0 25 1
49 2
25* 3
16
4
08 5
25*
i=4
21 0 25 1 25* 2 49 3 16 4 08 5 16 temp
第十章 内部排序
• • • • • •
基本概念 插入排序 快速排序 选择排序 归并排序 基数排序
10.1
基本概念
设含有n个记录的文件{R1,R2,...,Rn},其相应的关 键字为{K1,K2,...,Kn},将记录按关键字值非递减(或 非递增)顺序排列的过程,称为排序。 对所有的Ki=Kj (i≠j),若排序前Ri领先于Rj,排序后 Ri 仍领先于Rj,则称该排序方法是 稳定的 ,反之,称 为不稳定 的。 稳定性是对序列中的两个相同的关键字在初始序 列和最终有序序列中相对位置(即领先关系)是否 变化。
16
08
21
25
49
25*
16
08
21
25
49
25*
16
08
21
16
1
08 2
25* 3
25 4
49 5
i=2
Gap = 2
0
21
16
08
25*
25
49
21
16
08
25*
25
49
08
16
21
25*
25
49
08
16
1
21 2
25* 3
25 4
49 5
i=3
Gap = 1
0
08
16
21
25*
25
49
i=2 n
10.2
⑶ 结论
插入排序
1/. 直接插入排序的效率与待排文件的关键字排列有关; 2/. 直接插入排序的时间复杂度为O(n2);
3/. 直接插入排序是稳定的(这一点由函数中for 语句的 条件“<”保证的)。 void insertsort(sqlist &L , int n )
{ FOR (i=2; I<=n ;++I )
⑶ 希尔排序法是不稳定的。
void ShellSort(RecType R[],int n) /*希尔排序算法*/ { int i,j,d;RecType temp; d=n/2; /*d取初值n/2*/ while (d>0) { for (i=d;i<n;i++) /*将R[d..n-1]分别插入各组当前有序区*/ { j=i-d; while (j>=0 && R[j].key>R[j+d].key) { temp=R[j]; /*R[j]与R[j+d]交换*/ 希尔排序的时间复 R[j]=R[j+d];R[j+d]=temp; 杂度随d值取法的 j=j-d; 不同而不同,但d } 值的取法并无定式 } 。需保证最后一个 d=d/2; /*递减增量d*/ 增量必须为1。 } }
开始时 gap 的值较大,子序列中的对象较少,
排序速度较快;随着排序进展,gap 值逐渐变小,子
序列中对象个数逐渐变多,由于前面工作的基础,大 多数对象已基本有序,所以排序速度仍然很快。
⒊ 例:设初始关键字为:49 38 65 97 76 13 27 49' 55 04
第 一 趟 以 步 长 为 5 分 割 为 5 个 子 文 件 : (R1,R6) (R2,R7) (R3,R8) (R4,R6) (R5,R10),对每个子文件进行直接插入排序结果为: 13 27 49„ 55 04 49 38 65 97 76
⒉ 依据:⑴若待排序文件"基本有序",即文件中具有特性: L[i] < Max {L[j ]} 1≤j<i的记录数较少,
则文件中大多数记录都不需要进行插入。
⑵基本有序时,直接插入排序效率可以提高,接近于O(n)。
21
25 1 25
49 2
25* 3 25*
16
4
08 5
i=1
Gap = 3
0
21
49
经过比较和判断,将对象移到合适的位置。这时,数 据对象一般都存放在一个顺序的表中。
动态排序:
给每个对象增加一个链接指针,在排序的过程中
不移动对象或传送数据,仅通过修改链接指针来改变 对象之间的逻辑顺序,从而达到排序的目的。
10.2
插入排序
一. 直接插入排序 (最简单的排序方法)
⒈ 基本思想:依次将每个待排序的记录插入到一个有 序子文件的合适位置(有序子文件记录数增1) 例如:已有待排序文件为:21,25,49,25*,16 首先将文件的第一个记录,视为有序文件,然后从第 二个记录开始,直到最后一个记录,依次将他们插 入到有序文件的合适位置。
10.2
⒊ 算法分析
插入排序
⑴ 空间上,只需i,j两个整型变量和一个记录的辅助空间 r[0], r[0]作为“监视哨”,控制待插入元素相对于有序子文 件为最小时WHILE循环的结束,同时也用于暂存待插入元 素。 ⑵ 时间上,只包含比较关键字和移动记录两种操作。 ①比较次数 : 1/. 当待初始文件按关键字递增有序(正序)时: a.对每个记录只进行一次比较,整个排序过程共 进行了∑i=n-1次比较(最少); i=2 b.每个记录都要进行r[i]移到r[0]和r[0]移到r[j+1]两次 移动,因此共移动2(n-1)次(最少)。
n
10.2
插入排序
2/. 当待排序文件按关键字非递增有序(逆序)时 ① 记录r[i](i=2,3,...n)均要和前i-1个记录及r[0]进行比较, 整个排序过程共进行了 ∑ i=(n+2)(n-1)/2次比较(最多);
i=2 n
② 移动记录次数:每个记录都要进行r[i]移动到r[0]和r[0] 移动到r[j+1]两次移动,另外当r[i].key<r[j].key时, 还将r[j]移动到r[j+1],所以,当初始文件为正序时, 移动记录次数最少为2(n-1)次,当初始文件为逆序 时移动记录次数最多为 ∑ (i-1)+2(n-1)=(n+4)(n-1)/2次(最多)。
10.2
插入排序
13 27 49' 55 04 49 38 65 97 76
第二趟以步长为3对第一趟排序结果分割为3 个子文件: (R1,R4,R7,R10) (R2,R5,R8) (R3,R6,R9) 对每个子文件进行直接插入排序,结果为: 13 04 49' 38 27 49 55 65 97 76
4
5
temp
i=4 j=1 21 0 25 1
16 25*
2
25* 3
49 08 4 5
16
i=4 j=0
21 0 i=4 j = -1
16
25 1
25 2
25* 3
49 08 4 5
16 temp
16 21 0
21
25
25*
49 08
16
1
2
3
4
5
temp
void InsertSort(RecType R[],int n) /*对R[0..n-1]按递增有序进行 直接插入排序*/ { int i,j; RecType temp;
if (L[i-1]> L[ i ])
{ L[0]=L[i] ; for (j=I-1 ;L[0]<l[j] ; --j ) L[j+1]=L[j] ;
L[j+1]=L[0];
}
10.2
插入排序
二. 折半插入排序
由于是在有序子文件中确定插入的位置,因此 可用折半查找来代替直接插入排序法中的顺序查找, 从而可减少比较次数。
{m=(low+high )/ 2 ; IF (L[0]<L[m])
//<确保稳定,若改为≤,则不稳定}
high =m-1 ELSE low =m+1;} FOR (j=i-1 ; j>=high+1; --j) L[j+1]=L[j]; L[high+1]=L[0] }
//后移
确定插入位置所进行的折半查找,关键码的比较次数至多为 log2(n+1)次, } 移动记录的次数和直接插入排序相同,故时间复杂度仍为O(n2)。 是 一个稳定的排序方法。移动次数未变,故仍为O(n2)
i=5
16
21
25
25*
49 08 08
0
1
2
3
4
5
temp
完成
08 0 i=4 j=3 21 0 i=4 j=2 21 25
16
1
21 2
25 3
25* 4
49 5
i = 4 时的排序过程
25
1
25*
2
49 3
16 16 4 49 08 08 5 16 temp
16 25* 49 2 3
16
0
1
排序的时间开销:
排序的时间开销是衡量算法好坏的最重要的标志。
排序的时间开销可用算法执行中的数据比较次数与数据 移动次数来衡量。各节给出算法运行时间代价的大略估 算一般都按平均情况进行估算。对于那些受对象关键码
序列初始排列及对象个数影响较大的,需要按最好情况
和最坏情况进行估算。
静态排序: 排序的过程是对数据对象本身进行物理地重排,
10.2
插入排序
三. 希尔排序(Shell`s Methool)(又称为缩小增量排序)
直接插入排序算法简单,在n值较小时,效率比较高,在n值很大 时,若序列按关键码基本有序,效率依然较高,其时间效率可提 高到O(n)。希尔排序即是从这两点出发,给出插入排序的改进方 法
⒈ 基本思想:分割成若干个较小的子文件,对各个子文件分别进 行直接插入排序,当文件达到基本有序时,再对整个文件进行一 次直接插入排序。
mid
low high
23 0
21 1
25 2
25* 3
49
23 16 5
08 6
4
10.2
插入排序
Void binsort(sqlist &L ,int n )
{ FOR (i=2 ; I<=n ; ++I) { l[0]=l[I]; low=1; high = I-1 ;
WHILE (low<=high )
4 4
5 5
6 6
7 7
8 8
9 (d=2 执行结果) 9 (d=1 执行结果)
对特定的待排序对象序列,可以准确地估算关键 码的比较次数和对象移动次数。
但想要弄清关键码比较次数和对象移动次数与增 量选择之间的依赖关系,并给出完整的数学分析, 还没有人能够做到。
Knuth利用大量的实验统计资料得出,当 n 很大 时,关键码平均比较次数和对象平均移动次数大约 在 n1.25 到 1.6n1.25 的范围内。这是在利用直接插入 排序作为子序列排序方法的情况下得到的。
10.1
基本概念
内部排序 :待排序文件的全部记录存放在内存
进行的排序,称为内部排序。
外部排序:排序过程中需要进行内外存数据交
换的排序,称为外部排序。
10.1
内排序分类
基本概念
按排序过程依据的原则分为:插入排序 交换排序 选择排序 归并排序
基数排序
按排序过程所需的工作量分:简单排序 O(n2) 先进排序 O(nlogn) 基数排序 O(d.n)
for (i=1;i<n;i++)
{ temp=R[i]; j=i-1; /*从右向左在有序区R[0..i-1]找R[i]的插入位置*/
while (j>=0 && temp.key<R[j].key)
{ R[j+1]=R[j]; /*将关键字大于R[i].key的记录后移*/ j--;
}
R[j+1]=temp; } } /*在j+1处插入R[i]*/
例11.1 设待排序的表有10个记录,其关键字分别为 {9,8,7,6,5,4,3,2,1,0}。说明采用直接插入排序方法进 行排序的过程。
初始关键字 i=1 i=2 i=3 i=4 i=5 i=6 i=7 i=8 i=9 9 [8 [7 [6 [5 [4 [3 [2 [1 [0 8 9] 8 7 6 5 4 3 2 1 7 7 9] 8 7 6 5 4 3 2 6 6 6 9] 8 7 6 5 4 3 5 5 5 5 9] 8 7 6 5 4 4 4 4 4 4 9] 8 7 6 5 3 3 3 3 3 3 9] 8 7 6 2 2 2 2 2 2 2 9] 8 7 1 1 1 1 1 1 1 1 9] 8 0 0 0 0 0 0 0 0 0 9]
第三趟以步长为1对第二趟排序结果进行直接插入排序,结果为:
04 13 27 38 49' 49 55 65 76 97
10.2
4.希尔排序的特点
插入排序
⑴ 子文件(子序列)的构成不是简单地“逐段分割” ,而是将相隔某个“增量”的记录组成一个子文件 。 ⑵ 增量序列应是递减,且最后一个必须为1。
如上例的增量序列为:dlta[0..2],其值分别为:5,3,1
例11.2 设待排序的表有10个记录,其关键字分别为 {9,8,7,6,5,4,3,2,1,0}。说明采用希尔排序方法进行排 序的过程。
初始状态 9 8 7 6 5 4 3 2 1 0 (连线部分为下一趟作准备)
d=5
4
3
2
1
0
9
8
7
6
5 (d=5 执行结果)
d=2 d=1
0 0
1 1
2 2
3 3