数据结构第九章
数据结构第九章
9.4索引文件
索引文件由主文件和索引表构成。主文件为文件本身。索引 表指明逻辑记录和物理记录之间的对应关系。索引表由若干 索引项组成。一般索引项由主关键字和该关键字所在记录的 物理地址组成。索引表必须按主关键字有序,而主文件本身 则可以按主关键字有序或无序。 主文件按主关键字有序称索引顺序文件(Indexed Sequential File)。在ISF中,对一组记录建立一个索引项称为稀疏索引 。主文件按主关键字无序称索引非顺序文件(Indexed Non Sequential File)。必须为每个记录建立一个索引项,称为稠 密索引。将索引非顺序文件简称索引文件。索引非顺序文件 主文件无序,适合随机存取,不适合顺序存取。索引顺序文 件的主文件是有序的,适合随机存取、顺序存取。索引顺序 文件的索引是稀疏索引。索引占用空间较少,是最常用的一 种文件组织。最常用的索引顺序文件:ISAM文件和VSAM 文件。
对于字符流文件来说,查找操作是比较困难的。但管理简单 ,所以,操作不多的文件较适于采用字符流的无结构方式。 记录式的有结构文件可把文件中的记录按各种不同的方式排 列,构成不同的逻辑结构,以便用户对文件中的记录进行修 改、追加、查找和管理等操作。
文件的操作主要有两类:检索和维护 检索即在文件中查找满足给定条件的记录。文件的检索有以 下三种方式:
维护操作包括:对文件进行记录的插入、删除及修改等更新 操作。
文件的存储结构
文件的存储结构是指文件在外存上的组织方式。文件在外存 上的基本的组织方式有四种:顺序组织,索引组织,散列组 织和链组织;对应的的文件名称分别为:顺序文件、索引文 件、散列文件和多关键字文件。文件组织的各种方式往往是 这四种基本方式的结合。 选择哪一种文件组织方式,取决于对文件中记录的使用方式 和频繁程度、存取要求、外存的性质和容量。 评价一个文件组织的效率,是执行文件操作所花费的时间和 文件组织所需的存储空间。
第9章 数据结构
数据项:数据项是数据的不可分割的最小标识单位。数据元素是由若
干个数据项组成的。 如:书名、书号、作者名称为数据元素的数据项
数据结构
数据结构概述: 数据结构概述:
数据结构是由一个逻辑结构S,一个定义在S上的基本运算 集△和一个存储实现D所构成的整体(S,△,D)。 数据结构包括逻辑结构 基本运算 逻辑结构和基本运算 逻辑结构 基本运算两部分: •逻辑结构是用来完成数据表示的 •基本运算是用来完成数据处理的。
M
栈顶 top→ 入栈 退栈 ↓ ↑ an a2 栈底 bottom→ a1
队列的基本概念
队列(queue) 队列(queue)是指允许在一端进行插入而在另一端进行删除 的线性表。 允许插入的一端称为队尾 允许删除的一端称为排头(也称为队头) 显然,在队列这种数据结构中,最先插入的元素将最先能够 被删除,最后插入的元素将最后被删除。因此,队列又称为 “先进先出”(First In First Out,FIFO)或“后进后出” 先进先出” Out,FIFO)或“后进后出” (Last In Last Out,LILO)的线性表。 Out,LILO)的线性表。
数据的逻辑结构基本概念
数据的逻辑结构有两个要素: 数据的逻辑结构有两个要素: 逻辑结构有两个要素 一是数据元素的集合,通常记为D 一是数据元素的集合,通常记为D; 二是据元素之间的前后件关 通常记为R 系,通常记为R。
逻辑结构—线性结构和非线性结构
第9章 数据结构
教学目的
•了解数据结构的基本概念 •了解数据的逻辑结构和存储结构 •了解栈、队列及线性链表的概念及运算 了解栈、
数据结构的基本概念
数据、 数据、数据元素和数据项 数据结构 数据的逻辑结构
数据结构类型
大学数据结构课件--第9章 查找
二叉排序树既有类似于折半查找的特性,又采用了链表存储,它是动态 查找表的一种适宜表示。
注:若数据元素的输入顺序不同,则得到的二叉排序树形态 也不同!
17
二、二叉树的插入和删除操作
1、二叉排序树的插入和查找操作
例:输入待查找的关键字序列=(45,24,53,12,90)
折半查找举例:
已知如下11个元素的有序表:
(05 13 19 21 37 56 64 75 80 88 92), 请查找关键字为21和85的数据元素。
Low指向待查元 素所在区间的下 界
mid指向待查元素所在 high指向待查元素所
区间的中间位置
在区间的上界
8
9.1.2 折半查找(又称二分查找或对分查找)
balance。这样,可以得到AVL树的其它性质:
❖ 任一结点的平衡因子只能取:-1、0 或 1;如果树中任 意一个结点的平衡因子的绝对值大于1,则这棵二叉树 就失去平衡,不再是AVL树;
24
三、平衡二叉树
例:判断下列二叉树是否AVL树?
-1
1
-1
0
0
1
0
(a) 平衡树
2
-1
0
0
1
0
(b) 不是平衡树
(1)p为叶子结点,只需修改p双亲f的指针f->lchild=NULL或 f->rchild=NULL
(2)P只有左子树或右子树 ❖ P只有左子树,用P的左孩子代替P ❖ P只有右子树,用P的右孩子代替P
(3)P左、右子树均非空 (P左子树的根C的右子树分支找到S,S的右子树为空) ❖ P的左子树成为双亲f的左子树,P的右子树成为S的右子树 ❖ S的左子树成为S的双亲Q的右子树,用S取代p; 若C无右子树,用C取代p
数据结构第9章 排序
数据结构第9章排序数据结构第9章排序第9章排名本章主要内容:1、插入类排序算法2、交换类排序算法3、选择类排序算法4、归并类排序算法5、基数类排序算法本章重点难点1、希尔排序2、快速排序3、堆排序4.合并排序9.1基本概念1.关键字可以标识数据元素的数据项。
如果一个数据项可以唯一地标识一个数据元素,那么它被称为主关键字;否则,它被称为次要关键字。
2.排序是把一组无序地数据元素按照关键字值递增(或递减)地重新排列。
如果排序依据的是主关键字,排序的结果将是唯一的。
3.排序算法的稳定性如果要排序的记录序列中多个数据元素的关键字值相同,且排序后这些数据元素的相对顺序保持不变,则称排序算法稳定,否则称为不稳定。
4.内部排序与外部排序根据在排序过程中待排序的所有数据元素是否全部被放置在内存中,可将排序方法分为内部排序和外部排序两大类。
内部排序是指在排序的整个过程中,待排序的所有数据元素全部被放置在内存中;外部排序是指由于待排序的数据元素个数太多,不能同时放置在内存,而需要将一部分数据元素放在内存中,另一部分放在外围设备上。
整个排序过程需要在内存和外存之间进行多次数据交换才能得到排序结果。
本章仅讨论常用的内部排序方法。
5.排序的基本方法内部排序主要有5种方法:插入、交换、选择、归并和基数。
6.排序算法的效率评估排序算法的效率主要有两点:第一,在一定数据量的情况下,算法执行所消耗的平均时间。
对于排序操作,时间主要用于关键字之间的比较和数据元素的移动。
因此,我们可以认为一个有效的排序算法应该是尽可能少的比较和数据元素移动;第二个是执行算法所需的辅助存储空间。
辅助存储空间是指在一定数据量的情况下,除了要排序的数据元素所占用的存储空间外,执行算法所需的存储空间。
理想的空间效率是,算法执行期间所需的辅助空间与要排序的数据量无关。
7.待排序记录序列的存储结构待排序记录序列可以用顺序存储结构和和链式存储结构表示。
在本章的讨论中(除基数排序外),我们将待排序的记录序列用顺序存储结构表示,即用一维数组实现。
数据结构--第九章
/*对记录数组r做简单选择排序,length为数组的长度*/
{ n=length;
for ( i=1 ; i<= n-1; ++i)
{k=i;
for ( j=i+1 ; j<= n ; ++j)
if (r[j].key < r[k].key ) k=j;
if ( k!=i)
{ x= r[i]; r[i]= r[k]; r[k]=x; } }
9.4.1 简单选择排序
基本思想:第i趟简单选择排序是指通过n-i次关键字 的比较,从n-i+1个记录中选出关键字最小的记录, 并和第i个记录进行交换。共需进行i-1趟比较,直到 所有记录排序完成为止。
选择排序示例见P240的图9.5所示。
返回主目录
.
简单选择排序的算法描述如下:
void SelectSort(RecordType r[], int length)
返回主目录
.
例 13
38
27
50 76 65 49
97
97
38
27
50 76 65 49
13 输出:13
27
38
49
50 76 65 97
13 输出:13
返回主目录
.
9.2 插入类排序
基本思想:在一个已排好序的记录子集的基础上,每一步将 下一个待排序的记录有序插入到已排好序的记录子集中,直
到将所有待排记录全部插入为止。
9.2.1 直接插入排序
基本操作是将第i个记录插入到前面i-1个已排好序的记录中, 具体过程为:将第i个记录的关键字Ki顺次与其前面记录的 关键字Ki-1,Ki-2,…K1进行比较,将所有关键字大于Ki的 记录依次向后移动一个位置,直到遇见一个关键字小于或者 等于Ki的记录Kj,此时Kj后面必为空位置,将第i个记录插 入空位置即可。
数据结构-第9章
下面讨论顺序查找的实现。
假定有n个记录r0, r1, …, rn-1 顺序地存放在记录数组r中, 其中第i个记录的关键字值为ri ·key 。 如果给定一个关键数据k, 则用k依次与r0 ·key, r1·key, …进行相等比较, 一旦找到某一个记 录的关键字值与k相等, 即ri ·key =k, 则查找成功, 回送下标i。
第9章 查找
如果允许增设一个虚拟记录rn(只要不引起数组r的下标 溢出即可)作为循环控制的边界, 上面算法中的循环控制条件可 以减少一个, 而得到如下较快的顺序查找算法: 算法 9.2 Void Sequrt-Search2 (struct node r[], int n, int k)
5123143477391104
第9章 查找
若用整型变量low、 m、 high分别表示被查区间的第一个、 中间一个和最后一个记录的下标, 则开始查找时有low=0, high =7, m=[(0+7)/2]=3, 第一个、 中间一个和最后一个记录 的关键字值分别为 r0·key、 r3·key 和r7·key。 假设要 查找k=73的记录, 则折半查找过程如下:
{ int i=0;
r[n]·key=k; while (r[i]·key!=k) i=i+1; if(i<n) printf("%3d, it is r[%2d]", k, i); else prnitf("%3d not found", k);
}
第9章 查找
算法分析: (1) 在最坏的情况下, 顺序查找需要比较n次, 即MSL=n。
(2) 假定各记录的查找机会均等, 即Pi=1/n, 由于查找第i个记 录需要比较i次, 即ci =i, 于是有
数据结构---第九章.
b b+L b+(m-1)L
^ fire seeks ^
数据结构---第九章 查找 19
to ^
int SeqSearch(Seqlist R, KeyType K) { R[0].key=K; for (i=n; R[i]!=K; i--); return(i); }//SeqSearch
数据结构---第九0],提高算法效率。 [性能分析] • 空间复杂度:一个辅助空间。 • 时间复杂度: 1) 查找成功时的平均查找长度 设表中各记录查找概率相等
8.1.2 有序表的查找 满足 R[i].key R[i+1].key, 1 i <n [折半(对半/二分)查找法] 0 1 2 3 4 5 6
7
8
9
10 11
05 13 19 21 37 56 64 75 80 88 92 low mid high =(low+high)/2
K=21 l 1 1 4 h 11 5 5 m 6 3 4 K=85 l 1 7 10 10 h m 11 6 11 9 11 10 9
数据结构---第九章 查找
b+(m-1)L
16
8.3.2 哈希函数的基本构造方法 构造原则: 算法简单,运算量小;
均匀分布,减少冲突。
[直接定址法] H(key)=a key + b 特点:计算简单,冲突最少。 [数字分析法] 取关键字的若干数位作为哈希地址。 例:8 1 3 4 6 5 3 2 (共70个记录,则取随机性好的两位) [平方取中法] 取关键字平方后的中间几位作为哈希地址。
p=97
[随机数法]
H(key) = random(key) 特点:较适于关键字长度不等时的情况。
数据结构第九章动态查找
当数据结构中元素数量较大,且元素顺序不重要时,可以使
哈希查找是一种基于哈希表的查找算法,通过将键映
射到哈希表中对应的槽位,快速定位到元素。
02
哈希查找的时间复杂度为O(1),即平均时间复杂度为
常数时间,具有很高的查找效率。
03
哈希查找适用于数据量较大且数据插入、删除频繁的
平衡二叉树
如AVL树和红黑树,保持树平衡以实现高效的查找、插入和删除操作。
B树和B+树
适用于磁盘或其它直接存储设备上的数据查找,能够减少磁盘I/O操作。
算法的优化与改进
01
哈希表的负载因子
合理设置哈希表的负载因子,以 平衡哈希表的查找性能和冲突率。
02
平衡二叉树的旋转 操作
在插入和删除节点时,通过旋转 操作保持树的平衡,提高查找效 率。
03
B树和B+树的分裂 与合并
在节点分裂和合并时,合理调整 节点数据,减少磁盘I/O操作。
实际应用案例分析
数据库索引
数据库索引使用哈希表、B树或B+树等数据结构,以 提高数据查找速度。
搜索引擎
搜索引擎使用倒排索引、B树或B+树等数据结构,快 速定位网页内容。
文件系统
许多现代文件系统使用B树或B+树等数据结构,以提 高文件查找、读取和写入速度。
THANKS
感谢观看
额外空间复杂度
对于某些动态查找算法,如二分查找,需要额外的空间来存储中间结果,因此 其空间复杂度为O(log n)。而哈希表查找等其他算法则不需要额外的空间,其 空间复杂度为O(1)。
05
动态查找的实践应用
数据结构的选择
哈希表
适用于快速查找,但需要处理哈希冲突。
数据结构第九章
•(2)索引顺序查找的优点是:
在表中插入或删除一个元素时,只要 找到该元素所属的块,然后在块内进行 插入和删除。因块内元素的存放是任 意的,所以插入和删除时不需移动大量 元素.所付出的代价是增加了存放索引 表的辅助空间。
Destroy(&ST); Search(ST, key); Traverse(ST, Visit());
} ADT StaticSearchTable
Create(&ST, n);
操作结果:构造一个含n个数据元素
的静态查找表ST。
Destroy(&ST); 初始条件:静态查找表ST存在; 操作结果:销毁表ST。
一、顺序查找表
以顺序表或线性链 表表示静态查找表
(1)回顾顺序表的查找过程:
kk
k
ST.elem
21 37 88 19 92 05 64 56 80 75 13
0 1 2 3 4 5 6 7 8 9 10 11
ST.Length
假设给定值 e=64,
要求 ST.elem[k] = e, 问: k = ?
对元素操作的应用函数;
操作结果:按某种次序对ST的每个元素
调用函数Visit()一次且仅一 次,一旦Visit()失败,则操 作失败。
假设静态查找表的顺序存储结构为
typedef struct { ElemType *elem;
// 数据元素存储空间基址,建表时 // 按实际长度分配,0号单元留空
key=60
ST.Length
(3)从后往前查的算法
int Search_Seq(SSTable ST, KeyType key) {
// 在顺序表ST中顺序查找其关键字等于 // key的数据元素。若找到,则函数值为 // 该元素在表中的位置,否则为0。
数据结构_第9章_查找2-二叉树和平衡二叉树
F
PS
C
PR
CL Q
QL SL S SL
10
3
18
2
6 12
6 删除10
3
18
2
4 12
4
15
15
三、二叉排序树的查找分析
1) 二叉排序树上查找某关键字等于给定值的结点过程,其实 就是走了一条从根到该结点的路径。 比较的关键字次数=此结点的层次数; 最多的比较次数=树的深度(或高度),即 log2 n+1
-0 1 24
0 37
0 37
-0 1
需要RL平衡旋转 (绕C先顺后逆)
24
0
-012
13
3573
0
01
37
90
0 53 0 53
0 90
作业
已知如下所示长度为12的表:
(Jan, Feb, Mar, Apr, May, June, July, Aug, Sep, Oct, Nov, Dec)
(1) 试按表中元素的顺序依次插入一棵初始为空的二叉 排序树,画出插入完成之后的二叉排序树,并求其在 等概率的情况下查找成功的平均查找长度。
2) 一棵二叉排序树的平均查找长度为:
n i1
ASL 1
ni Ci
m
其中:
ni 是每层结点个数; Ci 是结点所在层次数; m 为树深。
最坏情况:即插入的n个元素从一开始就有序, ——变成单支树的形态!
此时树的深度为n ; ASL= (n+1)/2 此时查找效率与顺序查找情况相同。
最好情况:即:与折半查找中的判ห้องสมุดไป่ตู้树相同(形态比较均衡) 树的深度为:log 2n +1 ; ASL=log 2(n+1) –1 ;与折半查找相同。
数据结构-第九章 查找
数据结构-第九章查找数据结构第九章查找在计算机科学中,数据结构是组织和存储数据的方式,以便能够高效地进行访问、操作和管理。
而查找,作为数据结构中的一个重要概念,在我们处理和分析数据的过程中起着关键作用。
查找,简单来说,就是在一组数据中寻找特定的元素。
这听起来似乎很简单,但实际上,它涉及到一系列复杂的算法和策略,以确保能够快速准确地找到我们所需的信息。
让我们先来了解一下顺序查找。
顺序查找是最简单也是最直观的查找方法。
它的基本思想就是从数据集合的开头,逐个元素地进行比较,直到找到目标元素或者遍历完整个集合。
这种方法对于小型数据集或者数据没有特定规律的情况是可行的,但效率相对较低。
想象一下,你要在一本没有索引的电话簿中查找一个人的号码,只能从头开始一个一个地翻,这就是顺序查找的过程。
与顺序查找相对的是二分查找。
二分查找要求数据集合是有序的。
它通过不断地将数据集一分为二,比较目标元素与中间元素的大小,从而缩小查找范围。
这种方法的效率比顺序查找高得多。
比如说,要在一本按照姓名拼音排序的电话簿中查找一个人,我们可以先比较中间的名字,如果目标在前面,就只在前半部分继续查找,反之则在后半部分查找,如此反复,大大提高了查找的速度。
除了上述两种常见的查找方法,还有哈希查找。
哈希查找的核心是通过一个哈希函数将元素映射到一个特定的位置。
哈希函数的设计至关重要,一个好的哈希函数能够使得元素均匀地分布在哈希表中,减少冲突的发生。
当我们要查找一个元素时,通过哈希函数计算出其可能的位置,然后进行比较。
如果哈希函数设计得不好,可能会导致大量的冲突,从而影响查找效率。
在实际应用中,选择合适的查找方法取决于多个因素。
数据的规模是一个重要的考虑因素。
如果数据量较小,顺序查找可能就足够了;但对于大规模的数据,二分查找或者哈希查找通常更合适。
数据的分布情况也会影响选择。
如果数据分布比较均匀,哈希查找可能效果较好;如果数据有序,二分查找则更具优势。
数据结构第九章
1 查找失败: · n=n i 1 n
假设被查找的记录在顺序表中的概率为p,不在顺序表中的概率为q,则
n
考虑了查找成功或失败两种情况下的平均查找长度为:
ASLsq=p(n+1)/2 +q(n+l)=(n+1)(1- p/2)
顺序查找小结
简单,查找效率却较低。 当已知各记录的查找频率不等时,可以改 变记录的存储次序:
顺序存储结构 顺序存储结构 线性链表
当顺序表中记录的个数非常大,建立了多级索引表的建立
可以有效地提高查找速度。
付出的代价是增加辅助存储空间和将顺序表分块排序; 好
处是不需要对全部记录进行排序。
9.3动态查找技术
内部结点
1
3 5 2 2~3 3~4 4 4~5 5~6 6 6~7 8 9
11 13 10 8~9 7~8 12 10~11 9~10
27:⑦—③—⑤—④
外部结点
130:7—11—13—12 —12~13
14 12~13 14~15
0 0~1
-1~0
1~2
11~12
13~14
图 9.2.2 描述二分查找过程的二叉判定树
1. 内部结点中的值为对应记录的序号; 2. 外部结点中的两个值表示查找不成功时给定值在记录中所 对应的记录序号范围。
二分查找法的查找效率
假设有序表中记录的个数恰好为:n=20+21+…+2k-1=2k-l则相 应的二叉判定树为深度k=log2(n+1)的满二叉树。在树的第i层 上总共有2i-1个记录结点,查找该层上的每个结点需要进行i次 比较。因此,当表中每个记录的查找概率相等时,查找成功的
把查找频率高的记录尽可能放到序列的前面, 把查找频率低的记录放到序列的后面。
《数据结构》课件(C语言)第09章
单链表存储结构原理
存储结构
单链表中的每个结点包含两部分,一部分是存储数据元素的数据域,另一部分是存储下 一个结点地址的指针域。
原理
单链表通过每个结点的指针域将各个结点按顺序链接起来,形成一个线性结构。在单链 表中,每个结点只有一个后继结点,除首结点外,每个结点有且只有一个前驱结点。
一维数组排序
使用顺序表实现一维数组的排序,如冒泡排 序、插入排序等。
字符串操作
使用顺序表实现字符串的存储和操作,如字 符串拼接、查找子串等。
03 链表及其存储结构
链表定义及分类
链表定义
链表是一种物理存储单元上非连续、非 顺序的存储结构,数据元素的逻辑顺序 是通过链表中的指针链接次序实现的。
VS
链表分类
邻接表
用链表表示图,每个链表节点表示一 条边。适用于稀疏图的存储。
十字链表
有向图的邻接表与逆邻接表的结合, 适用于有向图的存储。
邻接多重表
无向图的邻接表的改进,适用于无向 图的存储。
图的遍历算法
深度优先遍历
从某个顶点出发,尽可能深地访问图中的所有顶点,直到没有未 访问的顶点为止。
广度优先遍历
从某个顶点出发,逐层访问图中的所有顶点,直到没有未访问的 ,队头指针加1。
注意
03
当队尾指针到达数组末尾时,需要进行循环移动,即将队尾指
针移动到数组开头。
队列链式存储结构实现
入队操作
在链表尾部插入新节点,队尾指针指向新节 点。
出队操作
删除链表头部的节点,队头指针指向下一个 节点。如果链表为空,则队头指针和队尾指
针都指向空。
05 数组和广义表
《 数据结构第九章
4、折半插入排序 折半插入排序算法的描述如下:
1 void BinSort(RecordType r[ ], int length)
2 { /*对记录数组r进行折半插入排序,length为数组的长度*/
3 for(i=2; i<=length; ++i)
4 { x= r[i];
5 low=1; high=i-1;
例如,待排序列为39,80,76,41,13,29,50,78,30,11, 100,7,41,86。增量分别取5、3、1,则排序过程如图9.4所示。
图9.4 希尔排序过程示例
图9.4 希尔排序过程示例
2、算法实现 希尔排序算法如下:
1 void ShellInsert(SqList *L, int delta)
表插入排序算法描述如下:
1 void SLinkListSort(RecordType1 r[], int length)
2 { int n=length;
3 r[0].next=1; r[1].next=0; /*构造只有一个元素的有序静态循环链表*/
4 for(i=2; i<=n-1; i++)
整队(或排列)的操作。
排序的定义:
假设含有n个记录的序列为:{r1,r2,…,rn}
(9-1)
它们的关键字相应为:{k1,k2,…,kn}。
对式(9-1)的记录序列进行排序就是要确定序号1,2,…,n的一种排列:
{p1,p2,…,pn}
使其相应的关键字满足如下的非递减(或非递增)的关系:
kp1≤kp2≤…≤kpn
/*将待插入记录复制为哨兵*/
7 j=i-1;
8 while(L->r[0].key<L->r[j].key)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
i 1 i 1 n 1 n 1
140-14
平均情况下排序的时间复杂度为 o(n2)。 直接插入排序是一种稳定的排序方法。
折半插入排序 (Binary Insertsort)
基本思想是 : 设在顺序表中有一 个元素序列 V[0], V[1], …, V[n-1]。其中, V[0], V[1], …, V[i-1] 是已经排好序的元素。在插入V[i] 时, 利 用折半搜索法寻找V[i] 的插入位置。
折半插入排序的算法
#include "dataList.h"
140-15
插入排序 (Insert Sorting)
基本方法是:每步将一个待排序的元素,按其 排序码大小,插入到前面已经排好序的一组元 素的适当位置上, 直到元素全部插入为止。
直接插入排序 (Insert Sort)
基本思想是 : 当插入第i (i≥1) 个元素时,前面 的V[0], V[1], …, V[i-1]已经排好序。这时,用 V[i]的排序码与V[i-1], V[i-2], …的排序码顺序 进行比较,插入位置即将V[i]插入,原来位置 上的元素向后顺移。
140-11
直接插入排序的算法
#include "dataList.h" template <class T> void InsertSort (dataList<T>& L, int left, int right) { //依次将元素L.Vector[i]按其排序码插入到有序表 //L.Vector[left],…,L.Vector[i-1]中,使得 //L.Vector[left]到L.Vector[i]有序。 Element<T> temp; int i, j; for (i = left+1; i <= right; i++) if (L[i] < L[i-1]) { temp = L[i]; j = i-1;
140-13
最好情况下,排序前元素已按排序码从小到大 有序,每趟只需与前面有序元素序列的最后一 个元素比较1次,总的排序码比较次数为 n-1, 元素移动次数为0。 最坏情况下, 第 i 趟时第 i 个元素必须与前面 i 个元素都做排序码比较, 并且每做1次比较就要 做1次数据移动。则总排序码比较次数KCN和 元素移动次数RMN分别为
template <class T> void BinaryInsertSort (dataList<T>& L, const int left, const int right) { //利用折半搜索, 在L.Vector[left]到L.Vector[i-1]中 //查找L.Vector[i]应插入的位置, 再进行插入。 Element<T> temp; int i, low, high, middle, k; for (i = left+1; i <= right; i++) { temp = L[i]; low = left; high = i-1; while (low <= high) { //折半搜索插入位置 middle = (low+high)/2; //取中点
log
i 1
n 1
2
i 1 n log2 n
折半插入排序是一个稳定的排序方法。
140-18
当 n 较大时,总排序码比较次数比直接插入排 序的最坏情况要好得多,但比其最好情况要差。 在元素的初始排列已经按排序码排好序或接近 有序时,直接插入排序比折半插入排序执行的 排序码比较次数要少。折半插入排序的元素移 动次数与直接插入排序相同,依赖于元素的初 始排列。
140-7
各 趟 排 序 结 果 i=1
21 0
25 1
49 2
25* 3
16
4
08 5
21 0
25
1
49 2
25*
3
16 4
08 5
25
temp
i=2
21 0
25 1
49 2
25* 3
16 4
49 08 5 temp
140-8
i=3
21 0
25 1
49 2
25* 3
16 4
08 5
25*
i=4
140-19
希尔排序 (Shell Sort)
希尔排序方法又称为缩小增量排序。该 方法的基本思想是 : 设待排序元素序列有 n 个元素, 首先取一个整数 gap < n 作为 间隔,将全部元素分为 gap 个子序列, 所有距离为 gap 的元素放在同一个子序 列中,在每一个子序列中分别
140-20
第九章 排序
概述 插入排序 快速排序 交换排序 选择排序
140-1
概述
排序:将一组杂乱无章的数据按一定的规律 顺次排列起来。 数据表(datalist): 它是待排序数据元素的有限 集合。
排序码(key): 通常数据元素有多个属性域, 即 多个数据成员组成, 其中有一个属性域可用来 区分元素, 作为排序依据。该域即为排序码。 每个数据表用哪个属性域作为排序码,要视 具体的应用需要而定。
140-2
排序算法的稳定性: 如果在元素序列中有两 个 元素r[i]和r[j], 它们的排序码 k[i] == k[j] , 且在 排序之前, 元素r[i]排在r[j]前面。如果在排序 之后, 元素r[i]仍在元素r[j]的前面, 则称这个排 序方法是稳定的, 否则称这个排序方法是不稳 定的。 内排序与外排序: 内排序是指在排序期间数据 元素全部存放在内存的排序;外排序是指在排 序期间全部元素个数太多,不能同时存放在内 存,必须根据排序过程的要求,不断在内、外 存之间移动的排序。
140-12
do { L[j+1] = L[j]; j--; } while (j >= left && temp < L[j]); L[j+1] = temp;
} };
算法分析 设待排序元素个数为currentSize = n, 则该算法 的主程序执行n-1趟。 排序码比较次数和元素移动次数与元素排序码 的初始排列有关。
140-25
L[j+gap] = temp; } } while (gap > 1); }; 算法分析
//将vector[i]回送
Gap的取法有多种。最初 shell 提出取 gap = n/2,gap = gap/2,直到gap = 1。knuth 提 出取 gap = gap/3 +1。还有人提出都取奇数 为好,也有人提出各 gap 互质为好。 对特定的待排序元素序列,可以准确地估算排 序码的比较次数和元素移动次数。
140-3
排序的时间开销: 排序的时间开销是衡量算法 好坏的最重要的标志。排序的时间开销可用算 法执行中的数据比较次数与数据移动次数来衡 量。 算法运行时间代价的大略估算一般都按平均情 况进行估算。对于那些受元素排序码序列初始 排列及元素个数影响较大的,需要按最好情况 和最坏情况进行估算。 算法执行时所需的附加存储: 评价算法好坏的 另一标准。
140-5
template <class T> class dataList { //数据表类定义 private: Element <T>* Vector; //存储排序元素的向量 int maxSize; //向量中最大元素个数 int currentSize; //当前元素个数 public: datalist (int maxSz = DefaultSize) : //构造函数 maxSize(maxSz), currentSize(0) { Vector = new Element<T>[maxSize]; } int Length() { return currentSize; } //取表长度 void Swap (Element<T>& x, Element<T>& y) { Element<T> temp = x; x = y; y = temp; } int Partition (const int low, const int high); //快速排序划分 }; 140-6
21
25*
25
49
140-23
08
16Βιβλιοθήκη 2125*25
49
i=3
Gap = 1
0
1
2
3
4
5 49
08
16
21
25*
25
希尔排序的算法
#include "dataList.h" template <class T>
140-24
void Shellsort (dataList<T>& L, const int left, const int right) { int i, j, gap = right-left+1; //增量的初始值 Element<T> temp; do { gap = gap/3+1; //求下一增量值 for (i = left+gap; i <= right; i++) if (L[i] < L[i-gap]) { //逆序 temp = L[i]; j = i-gap; do { L[j+gap] = L[j]; j = j-gap; } while (j >= left && temp < L[j]);