You are on page 1of 156

第7章 查找

教学内容
 7.1 查找的基本概念
 7.2 线性表的查找
 7.3 树表的查找
 7.4 散列表的查找
教学目标
 熟练掌握顺序表和有序表(折半查找)的查
找算法及其性能分析方法;
 熟练掌握二叉排序树的构造和查找算法及其
性能分析方法;
 掌握二叉排序树的插入算法,掌握二叉排序
树的删除方法;
 熟练掌握散列函数(除留余数法)的构造
 熟练掌握散列函数解决冲突的方法及其特点
7.1 查找的基本概念
 查找的基本概念
查找表
 由同一类型的数据元素(或记录)构成的集合
查找表常用的操作
 查询某个“特定的”数据元素是否在表中;
 查询某个“特定的”数据元素的各种属性;
 在查找表中插入一元素;
 从查找表中删除一元素。
静态查找表
 对查找表没有修改操作(插入和删除)
7.1 查找的基本概念
 查找的基本概念
动态查找表
 对查找表有修改操作
关键字
 记录中某个数据项的值,可用来标识一个记录
主关键字
 能唯一地标识一个记录的关键字
次关键字
 可以标识若干个数据元素
查找成功
 若表中存在特定元素,称查找成功。
7.1 查找的基本概念
 查找方法评价
时间复杂度
空间复杂度
平均查找长度 ASL(Average Search Length)
 为确定记录在表中的位置,需与给定值进行比较的关
键字的个数的期望值叫查找算法的 ASL 。
n
对含有n个记录的表,ASL   pi ci
i 1
n

 pi  1
其中:pi 为查找表中第i个元素的概率,
i 1

ci 为找到表中第i个元素所需比较次数
7.2 线性表的查找
 7.2.1 顺序查找
 7.2.2 折半查找
 7.2.3 分块查找
7.2.1 顺序查找
 顺序查找
查找过程
 从表的一端开始逐个进行记录的关键字和给定值的比

应用范围
 顺序表或线性链表表示的静态查找表
 表内元素之间无序
typedef struct {
顺序表的表示 KeyType key; // 关键字域
typedef struct { InfoType otherinfo;
ElemType *R; // 表基址}ElemType;
int length; // 表长
}SSTable;
7.2.1 顺序查找
 第 2 章在顺序表 L 中查找值为 e 的数据元素
int LocateElem(SqList L,ElemType e)
{
for (i=0;i< L.length;i++)
if (L.elem[i]==e) return i+1;
return 0;
}
改进:把待查关键字 key 存入表头(“哨兵”),
从后向前逐个比较,可免去查找过程中每一步都要
检测是否查找完毕,加快速度。
7.2.1 顺序查找
 带“哨兵”的顺序查找
int Search_Seq(SSTable ST, KeyType key){
// 若成功返回其位置信息,否则返回 0
ST.R[0].key =key;
for( i=ST.length; ST.R[i].key!=key; - - i );
return i;
}
顺序查找 i i
ST.elem
64 21 37 88 19 92 05 64 56 80 75 13
0 1 2 3 4 5 6 7 8 9 10 11
key = 64 ST.Length

i i
ST.elem
60 21 37 88 19 92 05 64 56 80 75 13
0 1 2 3 4 5 6 7 8 9 10 11

key = 60 ST.Length
7.2.1 顺序查找
 顺序查找的性能分析
空间复杂度
 一个辅助空间 O(1)
时间复杂度 O(n)
平均查找长度
 查找成功时的平均查找长度
 设表中各记录查找概率相等
 ASL=(1+2+ ... +n)/n =(n+1)/2
 查找不成功时的平均查找长度
 ASL=n+1
7.2.1 顺序查找
 顺序查找算法的特点
优点
 算法简单,对表结构无任何要求,即适用于顺序结
构,也适用于链式结构,无论记录是否按关键字有序
均可应用。
缺点
 平均查找长度较大,查找效率较低
 当 n 很大时,不宜采用顺序查找
7.2.2 折半查找
 折半查找
查找过程:每次将待查记录所在区间缩小一半
适用条件:采用顺序存储结构的有序表
算法实现
 设表长为 n , low 、 high 和 mid 分别指向待查元素
所在区间的上界、下界和中点, k 为给定值
 初始时,令 low=0 , high=n-
1 , mid=(low+high)/2
 让 k 与 mid 指向的记录比较
 若 k==r[mid].key ,查找成功
 若 k<r[mid].key ,则 high=mid-1
 若 k>r[mid].key ,则 low=mid+1
 重复上述操作,直至 low>high 时,查找失败
7.2.2 折半查找
 数组 a 中存放从小到大排好序的 n 个整数,
查找给定值 k 在数组中的下标;若查找失
败,返回 -1 。
找 37
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
5 13 19 21 37 56 64 75 80 88 92 100 111 120 125

low mid high

查找成功
7.2.2 折半查找

找 90
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
5 13 19 21 37 56 64 75 80 88 92 100 111 120 125

low mid high

查找失败
7.2.2 折半查找
 折半查找算法
int Search(SSTable ST,KeyType key)
{ int low,high,mid;
low=1; high=ST.length;
while(low<=high )
{
mid=(low+high)/2;
if(k>ST. R[mid].key) low=mid+1;
else if (k==ST. R[mid].key) return mid;
else high=mid-1;
}
return 0;
}
分析折半查找的平均查找长度
先看一个具体的情况,假设:
n=11
i 1 2 3 4 5 6 7 8 9 10 11
Ci 3 4 2 3 4 1 3 4 2 3 4
判定树 6
3 9
1 4 7 10
2 5 8 11
7.2.2 折半查找
 判定树
折半查找的过程可以用二叉树来描述,树中的每
个结点对应有序表中的一个记录,结点的值为该
记录在表中的位置。把当前查找区间的中间位置
作为根,左子表和右子表分别作为根的左子树和
右子树。由此得到的二叉树称为折半查找的判定
树。
7.2.2 折半查找
 判定树的构造方法
当 n=0 时,折半查找判定树为空;
当 n > 0 时,折半查找判定树的根结点是有序表
中序号为 mid=(n+1)/2 的记录,根结点的左子树
是与有序表 r[1] ~ r[mid-1] 相对应的折半查找判
定树,根结点的右子树是与 r[mid+1] ~ r[n] 相对
应的折半查找判定树。
7.2.2 折半查找
 加上外部结点的判定树
1 2 3 4 5 6 7 8 9 10 11
5 13 19 21 37 56 64 75 80 88 92

6 1
< = > 2
3 9
1 4 7 10 内结点

-1 2 3-4 5 6-7 8 9-10 11 h

1-2 2-3 4-5 5-6 7-8 8-9 10-11 11-


外结点
若所有结点的空指针域设置为一个指向一个方形结点的指针,称
方形结点为判定树的外部结点;对应的,圆形结点为内部结点。
7.2.2 折半查找
 练习
假定每个元素的查找概率相等,求查找成功时的
平均查找长度。
6 1
< = > 2
3 9
1 4 7 10 内结点

-1 2 3-4 5 6-7 8 9-10 11 h

1-2 2-3 4-5 5-6 7-8 8-9 10-11 11-


外结点
ASL = 1/11*(1*1 + 2×2 + 4×3+4*4 ) =
33/11=3
7.2.2 折半查找
 折半查找性能分析
具有 n 个结点的折半查找判定树的深度为ëlog 2 nû +1
查找成功
 在表中查找任一记录的过程,即是折半查找判定树中
从根结点到该记录结点的路径,和给定值的比较次数
等于该记录结点在树中的层数。
查找不成功
 查找失败的过程就是走了一条从根结点到外部结点的
路径,和给定值进行的关键字的比较次数等于该路径
上内部结点的个数。
7.2.2 折半查找
 折半查找的平均查找长度
1 次比较就查找成功的元素有 1 个( 20 ),即中间值;
推 2 次比较就查找成功的元素有 2 个( 21 ),即 1/4 处(或 3/4 )
导 处;
过 3 次比较就查找成功的元素有 4 个( 22 ),即 1/8 处(或 3/8 )处
程 …
4 次比较就查找成功的元素有 8 个( 23 ),即 1/16 处(或 3/16 )
处…
……
则第 h 次比较时查找成功的元素会有( 2h-1 )个;
7.2.2 折半查找
 折半查找算法的优缺点
优点
 比较次数少,查找速度快
缺点
 要求表有序,且顺序存储
 适用:不经常变动且查找频繁的有序表
7.2.2 折半查找
 课堂练习(多项选择)
使用折半查找算法时,要求被查文件
A.采用链式存储结构
B.记录的长度≤ 128

C.采用顺序存储结构

D.记录按关键字递增有序
索引顺序表
在建立顺序表的同时,建立一个索引。

例如: 顺序表
0 1 2 3 4 5 6 7 8 9 10 11 12 13 ……
17 08 21 19 14 31 33 22 25 40 52 61 78 46 ……

索引 21 0 40 5 78 10 ……

索引顺序表 = 索引 + 顺序

7.2.3 分块查找
 分块查找(索引顺序查找)
查找过程
 将表分成几块,块内无序,块间有序;先确定待查记录
所在块,再在块内查找
适用条件
 分块有序表
 每个子块中的关键字都比后一块中的关键字小 ( 但子表内部未
必有序 )
算法实现
 用数组存放待查记录,每个数据元素至少含有关键字域
 建立索引表,每个索引表结点含有最大关键字域和指向
本块第一个结点的指针
7.2.3 分块查找
 查找步骤分两步进行
对索引表使用折半查找法
确定了待查关键字所在的子表后,在子表内采用
顺序查找法
 因为各子表内部是无序表
 分块查找示例 索引表
22 48 86 查 38
1 7 13

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
22 12 13 8 9 20 33 42 44 38 24 48 60 58 74 57 86 53
查找成功
7.2.3 分块查找
 分块查找性能评价
ASLbs=Lb+Lw
其中:Lb ——查找索引表确定所在块的平均查找长度
Lw ——在块中查找元素的平均查找长度
若将表长为n 的表平均分成b 块,每块含s 个记录,并设表中每个记录
的查找概率相等,则:
(1)在索引表中用顺序查找确定所在块:
1 b
1 s
b 1 s 1 1 n
ASLbs 
b

j 1
j 
s
i 
i 1 2

2
 (  s)  1
2 s
( 2)在索引表中用折半查找确定所在块:
n s
ASLbs  l og2(  1) 
s 2
7.2.3 分块查找
分块查找优缺点
优点:插入和删除比较容易,无需进行大量移动。
缺点:要增加一个索引表的存储空间并对初始索
引表进行排序运算。
适用情况:如果线性表既要快速查找又经常动态
变化,则可采用分块查找。
7.2 线性表的查找
查找方法比较
顺序查找 折半查找 分块查找
ASL 最大 最小 两者之间

表结构 有序表、无序表 有序表 分块有序表


存储结构 顺序存储结构 顺序存储结构 顺序存储结构
线性链表 线性链表
7.3 树表的查找
 树表查找的特点
表结构在查找过程中动态生成 二叉排序树
对于给定值 key 平衡二叉树
 若表中存在,则成功返回; B- 树
 否则插入关键字等于 key 的记录 B+ 树
键树
7.3.1 二叉排序树
 二叉排序树
二叉排序树的定义
二叉排序树的查找
二叉排序树的插入
二叉排序树的构造
二叉排序树的删除
7.3.1 二叉排序树
 二叉排序树的定义
二叉排序树或是空树,或是满足如下性质的二叉

 若其左子树非空,则左子树上所有结点的值均小于根
结点的值;
 若其右子树非空,则右子树上所有结点的值均大于等
于根结点的值;
 其左右子树本身是一棵二叉排序树
7.3.1 二叉排序树
 课堂练习
下列图形中,哪个不是二叉排序树 ?
7.3.1 二叉排序树
 课堂练习 45

中序遍历二叉排序 12 53
树后的结果有什么
3 37 100
规律?
61
24 90
3 , 12 , 24 , 37 , 45 , 53 , 61 , 78 , 90 78
, 100
递增

得到一个关键字递增的有序序列
7.3.1 二叉排序树
 二叉排序树的查找
若查找的关键字等于根结点的关键字,则查找成

否则
 若给定值小于根结点的关键字,则继续在左子树上进
行查找;
 若给定值大于根结点的关键字,则继续在右子树上进
行查找。
7.3.1 二叉排序树
 二叉排序树的查找示例
二叉排序树
50
30 80
20 40 90
35 85
32 查找关键字 88
== 50 , 35 , 90 , 95 ,
7.3.1 二叉排序树
 二叉排序树查找的算法思想
若二叉排序树为空,则查找失败,返回空指针。
若二叉排序树非空,将给定值 key 与根结点的关
键字 T->data.key 进行比较:
 若 key 等于 T->data.key ,则查找成功,返回根结点
地址;
 若 key 小于 T->data.key ,则进一步查找左子树;
 若 key 大于 T->data.key ,则进一步查找右子树。
7.3.1 二叉排序树
 二叉排序树查找的算法描述
BSTree SearchBST(BSTree T, KeyType key) {
if((!T) || key==T->data.key) return T;
else if (key<T->data.key)
return SearchBST(T->lchild,key); // 在左子树中继续查找
else
return SearchBST(T->rchild,key); // 在右子树中继续查找

} // SearchBST
7.3.1 二叉排序树
 二叉排序树的插入
根据动态查找表的定义,“插入”操作在查找不
成功时才进行 ;
若二叉排序树为空树,则新插入的结点为新的根
结点;否则,新插入的结点必为一个新的叶子结
点,其插入位置由查找过程得到。

插入的元素一定在叶结点上
7.3.1 二叉排序树
二叉排序树的插入
插入思想
在二叉排序树中插入一个新结点 s 时,若
二叉排序树为空,则令新结点 s 为插入后二叉排序树
的根结点;否则,将结点 s 的关键字与根结点 T 的关
键字进行比较:
① 若相等: 不需要插入;
② 若 s.key<T->key :结点 s 插入到 T 的左子
树中;
③ 若 s.key>T->key :结点 s 插入到 T 的右子
树中。
7.3.1 二叉排序树
二叉排序树的插入
例:插入值为 98 的结点
root
63
63 root

55 90
∧ 55 90 ∧

58 70 98 ∧ 58 ∧ ∧ 70 ∧ ∧ 98 ∧

s
7.3.1 二叉排序树
 二叉排序树的插入 45

12 53

3 37 100
61
插入结点 20 24 90
20 78
7.3.1 二叉排序树
 二叉排序树的构造
从空树出发,经过一系列的查找、插入操作之
后,可生成一棵二叉排序树
示例 1
{10 , 18 , 3 , 8 , 12 ,
2 , 7}
10 10 10 10 10
18 3 18 3 18 3 18

10 10 8 8 12

3 18 3 18
2 8 12 2 8 12

7
7.3.1 二叉排序树
 二叉排序树的构造
示例 2 :给定关键字序列
= ( 45 , 24 , 53 , 45 , 12 , 24 , 90 )

查找成功, 查找成功,
返回 返回

则生成二叉排序树的过程为:
45

24 53

12 90
7.3.1 二叉排序树
 二叉排序树的构造
示例 3 :输入待查找的关键字序列
= ( 24 , 53 , 45 , 45 , 12 , 24 , 90 )
查找成功, 查找成功,
返回 返回
则生成的二叉排
序树: 注:若数据元素的输入
24
顺序不同,则得到的二
12 叉排序树形态也不同!
53

45 90
7.3.1 二叉排序树
 二叉排序树的构造
不同插入次序的序列生成不同形态的二叉排序树
40 , 24 , 12 , 37 , 12 , 24 , 37 , 40 ,
55 55
12
40
24
24 55
37
12 37 40
55
7.3.1 二叉排序树
二叉排序树的查找性能
对于含有同样关键字序列的一组结点,结点插
入的先后次序不同,所构成的二叉排序树的形态和深度
不同。而二叉排序树的平均查找长度 ASL 与二叉排序树
的形态有关,二叉排序树的各分支越均衡,树的深度浅,
其平均查找长度 ASL 越小。 例如:
12
45 24
37
24 53
45
53
12 37 93 93
(a) 输入关键字序列为 (b) 输入关键字序列为
{45,24,53,12,37,93} 时的二 {12,24,37,45,53,93} 时的二
叉排序树 叉排序树
7.3.1 二叉排序树
假设每个元素的查找概率相等,则它们的
平均查找长度分别是:
ASL=(1+2+2+3+3+3)/6=14/6
ASL=(1+2+3+4+5+6)/6=21/6
由此可见,在二叉排序树上进行查找时的平均查找
长度和二叉排序树的形态有关。
若考虑把 n 个结点,按各种可能的次序插入到二叉
排序树中,则有 n !棵二叉排序树(其中有的形态
相同),可以证明,对这些二叉排序树进行平均,
得到的平均查找长度仍然是 O(log2n) 。
二叉排序树的查找性能分析
1 ) 二叉排序树上查找某关键字等于给定值的结点过程,其实
就是走了一条从根到该结点的路径。
比较的关键字次数=此结点的层次数 ;
最多的比较次数=树的深度(或高度),即  log2 n+1
2) 一棵二叉排序树的平均查找长度为:
其中:
ni 是每层结点个数;
Ci 是结点所在层次数;
m 为树的深度(或高度)。
最坏情况:即插入的 n 个元素从一开始就有序,
—— 变成单支树的形态!
此时树的深度为 n , ASL= (n+1)/2
此时查找效率与顺序查找情况相同。
二叉排序树的查找性能分析
最好情况:即:与折半查找中的判定树相同(形态比较均衡)
树的深度为: log 2n  +1
ASL=log 2(n+1) –1 , 与折半查找相同。
7.3.1 二叉排序树
 二叉排序树的删除
对于二叉排序树,删除树上一个结点相当于删除
有序序列中的一个记录,删除后仍需保持二叉排
序树的特性。
可分三种情况讨论
 被删除的结点是叶子;
 被删除的结点只有左子树或者只有右子树;
 被删除的结点既有左子树,也有右子树。
( 1 )被删除的结点是叶子结点
被删关键字 = 88
20
例如 :
50
30 80
20 40 90
35 85
32 88
其双亲结点中相应指针域的值改为“空”
( 2 )被删除的结点只有左子树或者只有右子树
被删关键字 = 80
40
50
30 80
20 40 90
35 85
32 88
其双亲结点的相应指针域的值改为“指向被
删除结点的左子树或右子树”。
( 3 )被删除的结点既有左子树,也有右子树
被删关键字 = 50
50
40
30 80
20 40 90
35 85
32 88
前驱结点 被删结点 以其前驱替代之,然后
再删除该前驱结点
例:请从下面的二叉排序树中删除结点
P。 F
F P
P 法 C PR

C
1: CL
PR Q
QL
CL S
Q SL PR
QL
S
法 2:
F
SL PS
C PR
CL
Q
QL
SL S
SL
7.3.2 平衡二叉树
 平衡二叉树
何谓“平衡二叉树”?

如何构造“平衡二叉排序树”
7.3.2 平衡二叉树
 何谓“平衡二叉树”?
平衡二叉树又称 AVL 树 ( 发明者 G.M.
Adelson-Velsky 和 E.M. Landis) ,它是具有
如下性质的二叉排序树
 左、右子树是平衡二叉树;
 所有结点的左、右子树深度之差的绝对值不超过 1 。
 平衡因子
对于每个结点,其左子树的深度减去右子树的深

7.3.2 平衡二叉树
结点的平衡因子= HL-HR
判断下列二叉树是否平衡树?

5 5
4 8 4 8
2 2

平衡树
1 非平衡树

在平衡树中,结点的平衡因子可以是 1 , 0 , -1 。
7.3.2 平衡二叉树
 平衡二叉树的性质
任一结点的平衡因子只能取: -1 、 0 或 1 ;如
果树中某个结点的平衡因子的绝对值大于 1 ,则
这棵二叉树就失去平衡,不再是 AVL 树;
对于一棵有 n 个结点的 AVL 树,其高度保持在
O(log2n) 数量级, ASL 也保持在 O(log2n) 量级。
例:判断下列二叉树是否 AVL 树?
2
-1
1 -1 -1 0
0 0 1
0 1
0
0
(a) 平衡树 (b) 不平
7.3.2 平衡二叉树
最小不平衡子树:在平衡二叉树的构造过程中,以距
离插入结点最近的、且平衡因子的绝对值大于 1 的结
点为根的子树。
5

4 8

1
7.3.2 平衡二叉树
 如何构造“平衡二叉排序树”
 如果在一棵 AVL 树中插入一个新结点,就有可能造成失
衡,此时必须重新调整树的结构,使之恢复平衡。我们称
调整平衡过程为平衡旋转。
 平衡旋转可以归纳为:
 LL 平衡旋转

 RR 平衡旋转

 LR 平衡旋转

 RL 平衡旋转
7.3.2 平衡二叉树
 LL 平衡旋转
1 2 0
A A B
B 0 B 1 0
AR AR A
h h
BL
h B h B h B h B h+1
L R L R h AR h
BR
X
X
插入前 插入后,调整前
调整后
7.3.2 平衡二叉树
 LL 平衡旋转示例

10 1→2 8

8 12 7 10

7 9 6 9 12

6
7.3.2 平衡二叉树
 RR 平衡旋转
-2 0
-1
A A B

B -1 A 0
h
AL B 0 h
AL BR
h+1
h A h B
h B h B h B h B L L
L L R
R
X

插入前 插入后,调整前
调整后
7.3.2 平衡二叉树
 LR 平衡旋转
2 0
A
C
-1
B -1 AR 0
h B A
C
h B h-1 CL h-1 CR
L h B
L AR h
h-1 CL CR h-1
X
X
调整后
插入后,调整前
7.3.2 平衡二叉树
 RL 平衡旋转
-2 0
A
C
0
AL B 1 1
h A B
C
BR h AL h-1 CL h-1 CR
CR h-1
h BR h
h-1 CL
X
X
调整后
插入后,调整前
7.3.2 平衡二叉树
1 ) LL 平衡旋转:
A
若在 A 的左子树的左子树上插入
结点,使 A 的平衡因子从 1 增加 B
至 2 ,需要进行一次顺时针旋转。 C A
( 以 B 为旋转轴)

2 ) RR 平衡旋转:
若在 A 的右子树的右子树上插入 A
结点,使 A 的平衡因子从 -1 增
加至 -2 ,需要进行一次逆时针旋 B
转。 A C
( 以 B 为旋转轴)
7.3.2 平衡二叉树
3 ) LR 平衡旋转:
若在 A 的左子树的右子树上插入 A
结点,使 A 的平衡因子从 1 增加
C
B
至 2 ,需要先进行逆时针旋转,
再顺时针旋转。 B C
A
( 以插入的结点 C 为旋转轴)

4 ) RL 平衡旋转:
若在 A 的右子树的左子树上插入 A
结点,使 A 的平衡因子从 -1 增加 C
B
至 -2 ,需要先进行顺时针旋转,
再逆时针旋转。 A B
C
( 以插入的结点 C 为旋转轴)
7.3.2 平衡二叉树
 重要结论
当平衡的二叉排序树因插入结点而失去平衡时,
仅需对最小不平衡子树进行平衡处理即可。
平衡处理的关键是识别不平衡树是 AB 型还是
ABC 型。
由于经过旋转处理后的子树深度和插入之前相
同,因而不影响插入路径上所有祖先结点的平
衡。
例 1 :请将下面序列构成一棵平衡二叉排序
树:

( 13 , 24 , 37 , 90 , 53 )
-2
-1
0 -1
0
24 需要 RL 平衡旋
13

-1
0 0 -1
-2
0
需要 RR 平衡旋转 24 13 37
53

0 0 01
37 37 90

0
53
0
53

0 0
37 90
例 2 :设序列 {20 , 35 , 40 , 15 , 30 , 25} ,构造
平衡树。

20 35 30

35 20 40
20 35

40 15 30
15 25 40

25
课堂练习:设有关键码序列 {5, 4, 2, 8, 6, 9} ,构造平衡

4
5
LL 2 5
4 型
8
2
6
4 6
RL
型 2 6 RR
型 4 8
5 8
2 5 9
9
综上所述,在一个平衡二叉排序树上插入一个新结
点 S 时,主要包括以下三步:
( 1 )查找应插位置,同时记录离插入位置最近的
可能失衡结点 A ( A 的平衡因子不等于 0 )。
( 2 )插入新结点 S ,并修改从 A 到 S 路径上各
结点的平衡因子。
( 3 )根据 A 、 B 的平衡因子,判断是否失衡以及
失衡类型,并做相应调整。
7.3.3 B - 树
 B- 树
为什么引入 B- 树
定义
查找过程
插入操作
删除操作
7.3.3 B - 树
 为什么引入 B- 树?
前面介绍的折半查找和分块查找等,均适用于存
储在计算机内存中较小的文件,统称内查找法。
若要查找存储在外存中的大文件,内查找法都以
结点为单位进行查找,需反复地进行内、外存交
换,非常耗时。
对于存放于外存中的大量数据,查找的主要矛盾
变为减少访问外存次数。
 为此, 1970 年 ,R.Bayer 和 E.Mccreight 提出用
B_ 树作为索引组织文件 , 显著提高了查找速度。
7.3.3 B - 树
 B- 树定义
一颗 m 阶的 B- 树,或为空树,或为满足下列特
性的 m 叉树
 树中每个结点至多有 m 棵子树;
 若根结点不是叶子结点,则至少有两棵子树;

除根之外的所有非终端结点至少有 m/2 棵子树;
 所有叶子结点都出现在同一层次上,并且不带信息,
通常称为失败结点。失败结点实际上并不存在,指向
这些结点的指针为空。
7.3.3 B - 树
 B- 树定义
所有非终端结点最多有 m-1 个关键字,并且非终
端结点包含以下数据
n A0 K1 A1 K2 ··· Kn An

 ( n , A0 , K1 , A1 , K2 ,…, Kn , An )
 n ( m/2 1≤n≤m 1 )为关键字的个数;
 Ki ( 1≤i≤n )为关键字,且 Ki < Ki+1 ( 1≤i≤n-1 );
 Ai ( 0≤i≤n )为指向子树的指针,且指针 Ai 所指子树中所有结点的关键字均
小于 Ki+1 大于 Ki 。
7.3.3 B - 树
 B- 树示例 1 · 35 ·

1 · 18 · 2 · 43 · 78 ·

1 · 11 · 1 · 27 · 1 · 39 · 2 · 47 · 53 · 1 · 99 ·

F F F F F F F F F F F
7.3.3 B - 树
 B- 树的特点
平衡、有序、多路
 所有叶子结点均在同一层次,这体现出其平衡的特点
 树中每个结点中的关键字都是有序的,且关键字
Ki“ 左子树”中的关键字均小于 Ki ,而其“右子树”
中的关键字均大于 Ki ,这体现出其有序的特点。
 除叶子结点外,有的结点中有一个关键字,两棵子
树,有的结点中有两个关键字,三棵子树,这体现出
其多路的特点。
 3 阶 B -树又称为 2-3 树。
7.3.3 B - 树
 B - 树的存储结构
#define m 3
typedef struct BTNode {
int keynum; // 结点中关键字个数,结点大

struct BTNode *parent; // 指向双亲结点的指针
KeyType key[m+1]; // 关键字( 0 号单元未用)
struct BTNode *ptr[m+1]; // 子树指针向量
Record *recptr[m+1]; // 记录指针向量( 0 号单元不
用)
} BTNode, *BTree; // B- 树结点和 B- 树的类型
7.3.3 B - 树
 B - 树的查找
查找过程
 从根结点出发,顺着指针查找结点和在结点的关键字
中进行查找 交叉进行的过程。
若查找成功,则返回指向被查关键字所在结点的
指针和关键字在结点中的位置;
若查找不成功,则返回插入位置。
7.3.3 B - 树
 B - 树的查找算法思想(见算法 7.8 )
将给定值 key 与根结点的各个关键字 K1 , K2 ,
… ,Kj(1<=j<=m-1) 进行比较
 若 key=Ki ,则查找成功;
 若 key<K1, 则顺着指针 A0 所指向的子树继续向下查找
 若 Ki<key<Ki+1, 则顺着指针 Ai 所指向的子树继续向下
查找;
 若 key>Kj, 则顺着指针 Aj 所指向的子树继续向下查
找;
 重复上述过程,直到查找成功或到达叶子结点
7.3.3 B - 树
 B - 树的查找
查找 53
1 · 35 ·

1 · 18 · 2 · 43 · 78 ·

1 · 11 · 1 · 27 · 1 · 39 · 2 · 47 · 53 · 1 · 99 ·

F F F F F F F F F F F
7.3.3 B - 树
 B- 树的插入
利用 B- 树的查找算法找出插入的位置
按规则插入关键字
 插入一个关键字不是在树中添加一个叶子结点,而是
首先在最底层的某个非终端结点中添加一个关键字,
若该结点的关键字个数 n≤m-1 ,则插入完成,否则要
产生结点的分裂。
7.3.3 B - 树
 B- 树的插入
令 n 为被插入结点中关键字的个数,则插入的情
况有以下三种 ( m/2 1≤n≤m1)
 插入前结点中关键字个数 n<m-1 ,则直接插入即可 ;
 插入前结点中关键字个数 n=m-1 ,则需进行“结点
分裂”
 令 s = m/2, 在原结点中保留 (A0,K1,…, Ks-1,As-1), 建新结点
p=(As,Ks+1,…,Kn,An), 将( Ks , p )插入双亲结点。由于双亲
结点增加一个新纪录,所以必须对其重复上述步骤,直到根
结点。
 由于根结点无双亲,则由其分裂产生的两个结点的指
针 p 和 q, 以及关键字为 Ks 的纪录构成一个新的根结
点。此时, B- 树的高度增加 1.
例如 : 下列为 3 阶 B- 树 (2-3 树 )

50

3030
505050 8080
80

 20
 20
 40 6080
   40  608090
 60
 80
 90

插入关键字 = 60, 90, 30,


2 – 3 树——插入操作

18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52

11
结点只包含 1 个记录 插入新记录
2 – 3 树——插入操作

18 33

12 23 30 48

10 11 15 20 21 24 31 45 47 50 52
2 – 3 树——插入操作

结点只包含 2 个记录 插入新记录,分裂-提升

18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52

55
2 – 3 树——插入操作

结点只包含 2 个记录 插入新记录,分裂-提升

18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52 55
插入
2 – 3 树——插入操作

结点只包含 2 个记录 插入新记录,分裂-提升

18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52 55
分裂
2 – 3 树——插入操作

结点只包含 2 个记录 插入新记录,分裂-提升

18 33

12 23 30 48 52

10 15 20 21 24 31 45 47 50 55
提升
7.3.3 B - 树
B- 树的删除
和插入的考虑相反,首先必须找到待删
关键字所在结点,并且要求删除之后,结点
中关键字的个数不能小于 m/2-1 ,否则,要
从其左 ( 或右 ) 兄弟结点“借调”关键字,若
其左和右兄弟结点均无关键字可借 ( 结点中只
有最少量的关键字 ), 则必须进行结点的“合
并”。
7.3.3 B - 树
 B- 树的删除
在 B- 树上删除关键字可以分两步执行
① 利用 B- 树的查找算法找出该关键字所在结点。
② 然后根据关键字所在结点是否为叶子结点 ( 最底层非
终端结点 ) 有不同的处理方法
 若该结点为叶结点,则在叶结点中删去关键字。
 若该结点为非叶结点,且被删关键字为该结点中第 i 个
关键字 key[i] ,则可从指针 ptr[i] 所指的子树中找出最
小关键字 Y ,代替 key[i] 的位置,然后在叶结点中删去
Y。
因此, B- 树上删除关键字的本质是删除叶子结
点中的关键字。
B- 树的删除

从非叶结点删除 18 。

18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52

解决方法:将被删除记录用右边子树中的最小关键码 Y
代替( Y 一定在某个叶子结点中),然后再删除 Y 。
B- 树的删除

从非叶结点删除 18 。

20 33

12 23 30 48

10 15 21 24 31 45 47 50 52

解决方法:将被删除记录用右边子树中的最小关键码 Y
代替( Y 一定在某个叶子结点中),然后再删除 Y 。
7.3.3 B - 树
 在 B- 树的叶结点上删除关键字(三种情形讨论)
第一种情况 : 直接删
被删关键字所在结点中的关键字数目不小于 ,
m / 2

只需从该结点中删去该关键字 Ki 和相应指针 Ai ,树的其
他部分不变。
18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52
7.3.3 B - 树
 在 B- 树的叶结点上删除关键字
第一种情况
18 33

12 23 30 48

10 15 21 24 31 45 47 50 52

解决方法:直接删除 20 。
7.3.3 B - 树
 在 B- 树的叶结点上删除关键字
第二种情况:借兄弟结点的关键字
被删关键字所在结点中的关键字数目等于 m / 2 - 1 ,而
与该结点相邻的右兄弟 ( 或左兄弟 ) 结点中的关键字数目
大于 m / 2 - 1 ,则需将其兄弟结点中的最小 ( 或最大 ) 的关
键字上移至双亲结点中,而将双亲 结点中小于 ( 或大于 ) 且
紧靠该上移关键字的关键字下移至被删关键字所在结点中。
7.3.3 B - 树
 B- 树的删除
bt
示例:删除叶结点 50
a
45
b e
24 53 90
c d f g h
bt 3 37 50 61 70 100

a
45
b e
24 61 90
c d f g h
3 37 53 70 100
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 24

18 33

12 23 30 48

10 15 20 21 24 31 45 47 50 52
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 24
18 33

12 21 30 48

10 15 20 23 31 45 47 50 52

解决方法:向兄弟结点借一个记录,同时修改双亲
结点的记录。
7.3.3 B - 树
 在 B- 树的叶结点上删除关键字
第三种情况:兄弟结点不够借,合并结点
被删关键字所在结点和其相邻的兄弟结点中的关键字数目均
等于 - 1 。假设该结点有右兄弟,且其右兄弟结点地
址 m / 2
由双亲结点中的指针 Ai 所指,则在删去关键字之后,它所在
结点中剩余的关键字和指针,加上双亲结点中的关键字 Ki 一
起,合并到 Ai 所指兄弟结点中 ( 若没有右兄弟,则合并至左兄
弟结点中 ) 。如果因此使双 亲结点中的关键字数目小于m / 2
-
1 ,则依次类推作相应处理。
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 23
18 33

12 21 30 48

10 15 20 23 31 45 47 50 52

解决方法:兄弟结点不够借,需要合并相邻结点,
并影响双亲结点。
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 23
18 33

12 30 48

10 15 20 21 31 45 47 50 52
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 15
18 33

12 30 48

10 15 20 21 31 45 47 50 52
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 15
33

18 30 48

10 12 20 21 31 45 47 50 52
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 30
33

25 48

20 30 45 47 50 52
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 30

33 48

20 25 45 47 50 52

2-3 树的优点:能够以相对较低的代价保持树高平衡。

解决方法:兄弟结点不够借,需要合并相邻结点,
并影响双亲结点,这可能减少树的高度。
7.3.3 B - 树
 B- 树的删除
示例:删除叶结点 37 bt

a
45
b e
24 90
c d g h
3 37 61 70 100
bt

e
45 90

c g h
3 24 61 70 100
B 树
+

是 B- 树的一种变型
1 . B+ 树的结构特点:

※ 每个叶子结点中含有 n 个关键字和
n 个指向记录的指针;并且,所有叶
子结点彼此相链接构成一个有序链表,
其头指针指向含最小关键字的结点;
B 树
+

※ 每个非叶结点中的关键字 Ki 即为其

相应指针 Ai 所指子树中关键字的最大
值;
※ 所有叶子结点都处在同一层次上,

每个叶子结点中关键字的个数均介于
 m/2 和 m 之间。
B 树
+

2 .查找过程
※在 B+ 树上,既可以进行缩小范围的

※ 找,也可以进行顺序查找;
在进行缩小范围的查找时,不管成功
与否,都必须查到叶子结点才能结
束;
※ 若在结点内查找时,给定值≤ K , 则
i

应继续在 Ai 所指子树中进行查找;
B 树
+

3 .插入和删除的操作

类似于 B- 树进行,即必要时,也
需要进行结点的“分裂”或“归
并”。
B 树 +

root

50 96

15 50 62 78 96
sq

3 8 15 20 26 43 56 62 71 78 84 89
50 96
7.4 散列表的查找
 散列表的基本思想和相关术语
 散列函数的构造方法
 处理冲突的方法
 散列表的查找
7.4.1 散列表的基本概念
 散列表的基本思想
在记录的存储地址和它的关键字之间建立一个确
定的对应关系;这样,不经过比较,一次存取就
能得到所查元素。
 记录的存储位置与关键字之间存在对应关系
Loc(i)=H(keyi)
散列函数

hash
关键字 存储地址
集合 集合

 散列表的优点
查找速度极快 O(1), 查找效率与元素个数 n 无关
7.4.1 散列表的基本概念
 示例 1
若将学生信息按如下方式存入计算机,如:
将 2001011810201 的所有信息存入 V[01]
单元;
将 2001011810202 的所有信息存入 V[02]
单元;
…… 2001011810216 的信息
查找
将 2001011810231
 可直接访问 V[16] 的所有信息存入 V[31]
单元。
7.4.1 散列表的基本概念
 示例 2
数 据 元 素 序 列
(14 , 23 , 39 , 9 , 25 , 11) ,若规定
每个元素 k 的存储地址 H(k) = k ,请画出存
储结构图。
地址 … 9 … 1 … 1 … 2 2 2 … 3 …
内容 9 1
11 4
1 3
23 4 5
25 9
39
4
7.4.1 散列表的基本概念
 如何进行散列查找
地址 … 9 … 1 … 1 … 2 2 2 … 3 …
内容 9 1
11 4
1 3
23 4 5
25 9
39
4

根据散列函数 H(k) = k 进行查找


 查找 key=9, 则访问 H(9)=9 的地址,若内容为 9 则
成功;
 若查不到,则返回一个特殊值,如空指针或空记录。
7.4.1 散列表的基本概念
 散列表的相关术语
散列函数
 在记录的关键字与记录的存储地址之间建立的一种对
应关系叫散列函数。
 散列函数只是一种映象,所以散列函数的设定很灵
活,只要使任何关键字的散列函数值都落在表长允许
的范围之内即可。
散列表
 应用散列函数,由记录的关键字确定记录在表中的地
址,并将记录放入此地址,这样构成的表叫散列表。
散列查找
 又称哈希查找,利用散列函数进行查找的过程
7.4.1 散列表的基本概念
 散列表的相关术语
冲 突
 不同的关键码映射到同一个散列地址
 key1key2 ,但 H(key1)=H(key2)
 散列函数通常是一种压缩映象,所以冲突不可避免,
只能尽量减少;同时,冲突发生后,应该有处理冲突
的方法。
同义词
 具有相同函数值的两个关键字,叫该散列函数的同义

7.4.1 散列表的基本概念
 冲突现象举例
( 14 , 23 , 39 , 9 , 25 ,
11 )
散列函数: H(k)=k mod
0 1 2 3 4 5 6
7
14 23 39 6 个元素用 7
9 25 个
H(14)=14%7=0 11 地址应该足够 !
H(25)=25%7=4
有冲突 H(11)=11%7=4
同义词

冲突是不可能避免的,可通过构造好的哈希函数
减少冲突;还需要找到“处理冲突”的方法
7.4.2 散列表的构造方法
 散列函数的构造方法
数字分析法
平方取中法
折叠法
除留余数法
7.4.2 散列表的构造方法
 数字分析法
构造:对关键字进行分析,取关键字的若干位或
其组合作散列地址
适于关键字位数比散列地址位数大,且可能出现
的关键字事先知道的情况
例 有 80 个记录,关键字为 8 位十进制数,散列地址为 2 位十进制数
   

8 1 3 4 6 5 3 2 分析: 只取 8
8 1 3 7 2 2 4 2  只取 1
8 1 3 8 7 4 2 2  只取 3 、 4
8 1 3 0 1 3 6 7  只取 2 、 7 、 5
 数字分布近乎随机
8 1 3 2 2 8 1 7
所以:取任意两位或两位
8 1 3 3 8 9 6 7 与另两位的叠加作散列地址
8 1 3 6 8 5 3 7
8 1 4 1 9 3 5 5
7.4.2 散列表的构造方法
 平方取中法
构造
 取关键字平方后中间几位作散列地址
适于不知道全部关键字情况
 求“关键字的平方值”的目的是“扩大差别”
 示例
2589 的平方值为 6702921 ,可以取中间的 029
为地址
7.4.2 散列表的构造方法
 折叠法
构造:将关键字分割成位数相同的几部分,然后
取这几部分的叠加和做散列地址
种类
 移位叠加:将分割后的几部分低位对齐相加
 间界叠加:从一端沿分割界来回折送,然后对齐相加
适于关键字位数很多,且每一位上数字分布大致
均匀情况 例 关键字为 : 0442205864 ,散列地址位数为 4
5864 5864
4220 0224
04 移位叠加 04 间界叠加
10088 6092
H(key)=0088 H(key)=6092
7.4.2 散列表的构造方法
 除留余数法
构造:取关键字被某个不大于散列表表长 m 的数
p 除后所得余数作散列地址
 即 H(key)=key MOD p , p  m
特点
 简单、常用,可与上述几种方法结合使用
 p 的选取很重要; p 选的不好,容易产生同义词
 p 应为不大于 m 的素数
 或是
 不含 20 以下的质因子
为什么要对 p 加限制?
例如:
给定一组关键字为 : 12, 39, 18, 24, 33,
21 ,
若取 p=9, 则他们对应的哈希函数值将为 :
可见,若 p 中含质因子 3, 则所有
含质因子
3, 3, 0, 6, 6,33 的关键字均映射到“ 3 的倍
数”的地址上,从而增加了“冲突”的可
7.4.2 散列表的构造方法
 总之,选取散列函数应考虑以下因素:
散列表的长度(散列地址范围)
关键字的长度
关键字的分布情况
计算散列函数所需的时间
记录的查找频率
7.4.3 处理冲突的方法
 处理冲突的实际含义
为产生冲突的地址寻找下一个散列地址
 处理冲突的方法
开放定址法
再散列法
链地址法
建立一个公共溢出区
7.4.3 处理冲突的方法
 开放定址法
方法:当冲突发生时,形成一个探查序列;沿此
序列逐个地址探查,直到找到一个空位置(开放
的地址),将发生冲突的记录放到该地址中,即
Hi=(H(key)+di)MOD m, i=1,2,…,k(k  m-1)
 H(key)— 散列函数 ,m — 散列表表长 ,di — 增量序列
分类
 线性探测再散列: di =1,2,3,…,m-1
 二次探测再散列: di =1²,-1²,2²,-2²,3²,…,±k²(km/2)
 伪随机探测再散列: di = 伪随机数序列
开放定址法举例
1. 表长为 11 的散列表中已填有关键字为 17 , 60 , 29 的记录,
H(key)=key MOD 11, 现有第 4 个记录,其关键字为 38 ,按三
种处理冲突的方法,将它填入表中
0 1 2 3 4 5 6 7 8 9 10
38 38 60 17 29 38

(1) H(38)=38 MOD 11=5 冲突


H1=(5+1) MOD 11=6 冲突
H2=(5+2) MOD 11=7 冲突
H3=(5+3) MOD 11=8 不冲突
(2) H(38)=38 MOD 11=5 冲突
H1=(5+1²) MOD 11=6 冲突
H2=(5-1²) MOD 11=4 不冲突
(3) H(38)=38 MOD 11=5 冲突
假设产生的伪随机数为 9 ,则:
H1=(5+9) MOD 11=3 不冲突
7.4.3 处理冲突的方法
 再散列法
方法:构造若干个散列函数,当发生冲突时,计
算下一个散列地址,即: Hi=RHi(key) i=1,2,…,k
 RHi— 不同的散列函数
 特点:计算时间增加
 链地址法
方法:将所有关键字为同义词的记录存储在一个
单链表中,并用一维数组存放头指针
7.4.3 处理冲突的方法
 链地址法举例
已知一组关键字
(19,14,23,1,68,20,84,27,55,11,10,79) 散列函数
为: H(key)=key MOD 13, 用链地址法处理冲突
^
0 1 2 3 4 5 6 7 8 9 10 11 12

14 1 27 79 ^
^
68 55 ^
^
^
19 84 ^
20 ^
^ 注:有冲突的元素可以插
^
23 10 ^ 在表尾 , 也可以插在表头
11 ^
^
7.4.3 处理冲突的方法
 建立一个公共溢出区
思路
 除设立散列基本表外,另设立一个溢出向量表。
所有关键字和基本表中关键字为同义词的记录,
不管它们由散列函数得到的地址是什么,一旦发
生冲突,都填入溢出表。
7.4.4 散列表的查找
 散列表的查找 给定 k 值

给定值与关键字比较
计算 H(k)

Y
此地址为空
N
查找失败
Y
关键字 ==k
查找成功 N
按处理冲突
方法计算
Hi
举例
 在 0 ~ 10 的 散 列 地 址 空 间 中 , 对 关 键 字
(22 , 41 , 53 , 46 , 30 , 13 , 01 , 67) 构造哈希
表,选取哈希函数 H(K)=(3K)%11, 用链地址法处理冲
突。写出哈希表构造过程,并画出哈希表。1
0 2
ASL( 成功 )= (1*5+3*2) / 1 1 2
8 =11/8 2 3
3 3
ASL( 失败 )= 4 1
(1*6+2*2+3*3)/11 5 2
=19/11 6 3
7 1
8 1
9 1
10 1
7.4.4 散列表的查找
 课堂练习
对于关键字序列 (19,14,23,1,68,20,84,27,55,11,10, 79) ,
散列函数为 H(key)=key MOD 13, 用链地址法构造散列表,
并求出等概率下查找成功和查找失败时的平均查找长度。
^
0 1 2 3 4 5 6 7 8 9 10 11 12

14 1 27 79 ^
^
68 55 ^
^
ASLsucc=(1*6+2*4+3+4)/12=1.75
^
19 84 ^
20 ^
^ ASLunsucc=(1+5+1+3+1+1+3+2+1+1+3+2+1)/13=1.92
^
23 10 ^
11 ^
^
哈希表的查找及其分析
哈希表查找分析 :
从查找过程得知,哈希表查找的平均查找长
度实际上并不等于零。由于冲突的产生,使得哈希表
的查找过程仍然要进行比较,仍然要以平均查找长度
ASL 来衡量。
决定哈希表查找的 ASL 的因素:
• ( 1 )选用的哈希函数 ;
• ( 2 )选用的处理冲突的方法 ;
• ( 3 )哈希表饱和的程度,装载因子
α=n/m 值的大小( n— 记录数, m— 表的长
度)α 越小,发生冲突的可能性越小,而 α 越大,发生冲
显然,
突的可能性也越大。
哈希表的查找及其分析

一般情况下,可以认为选用的哈希函数是
“均匀”的,则在讨论 ASL 时,可以不考虑因素
( 1 )。
因此,哈希表的 ASL 是处理冲突方法和装载因子的函数。

用哈希表构造查找表时,可以选择一个适当的装填因
子  ,使得平均查找长度限定在某个范围内。

—— 这是哈希表所特有的特点。
小结
 熟练掌握顺序表和有序表(折半查找)的查找算法及其性能
分析方法;
 熟练掌握二叉排序树的构造和查找算法;
 熟练掌握二叉排序树的插入、删除方法;
 掌握平衡二叉树的定义及构造方法
 熟练掌握哈希函数(除留余数法)的构造
 熟练掌握哈希函数解决冲突的方法及其特点
开放地址法(线性探测法、二次探测法)
链地址法
练习
一、选择题
1. 如果要求一个线性表既能较快地查找,又能适
应动态变化的要求,则可采用 (①) 查找方法。
采用折半查找方法进行查找时,数据文件应为
(②) ,且限于 (③) 。要进行顺序查找,则线
性表 (④) 。
① : A. 分块 B. 顺序 C. 折半 D. 基
于树型
②③ : A. 有序表 B. 随机表 C. 散列存储
结构
D. 链式存储结构 E. 顺序存
储结构
F. 线性表
④ : A. 必须以顺序方式存储
①D②A③E④C
B. 必须以链式方式存储
2. 折半查找的查找速度 (①) 比顺序查找法的速
度快。设有 100 个元素,用折半法查找时,最
大比较次数是 (②) ,最小比较次数是 (③) 。
① : A. 一定 B. 不一定
②③ : A.25 B.50 C.10 D.7 E.4 F.2 G.1
①B②D③G
3. 设散列表长 m=14 ,散列函数 H(k)=k MOD 11 。
表中已有 4 个记录,如果用二次探测散列处理
冲突,关键字为 49 的记录的存储地址是 (D
)。
A.8 B.3 C.5 D.9
49%11=5 (49+12)%11=6 (49-12)%11=4
(49+22)%11=9
4. 当对一个线性表 R[60] 进行索引顺序查找(分
块查找)时,若共分成了 10 个子表,每个子表
有 6 个表项。假定对索引表和数据子表都采用
顺序查找,则查找每一个表项的平均查找长度
为 ( C) 。
A. 1 B.2 C.9 D.10
5. 散列函数有共同的性质,则函数值应当以( ) D
概率取其值域的每一个值。
A. 最大 B. 最小 C. 平均 D. 同

6. 设散列地址空间为 0~m-1 , k 为表项的关键码,
散列采用除留余数法,即 Hash(k)=k%p B 。为
了减少发生冲突的频率,一般取 p 为( )。
A.m B. 小于 m 的最大质数
C. 大于 m 的最小质数 D. 小于 m 的最大合数
7. 解决散列法中出现的冲突问题常采用的方法是
( D) 。
A. 数字分析法、除留余数法、平方取中法
B. 数字分析法、除留余数法、线性探查法
C. 数字分析法、线性探查法、双散列法
D. 线性探查法、双散列法、平方散列法
8. 采用线性探查法解决冲突时所产生的一系列后
继散列地址( )。 C
A. 必须大于等于原散列地址
B. 必须小于等于原散列地址
C. 可以大于或小于但不等于原散列地址
D. 对地址在何处没有限制
9. 对包含 n 个元素的散列表进行查找,平均查找
长度(C )。
A. 为 O(log2n) B. 为 O(n)
C. 不直接依赖于 n D. 上述三者都不是
二、应用题
1 、静态索引结构和动态索引结构的优缺点?
静态索引结构的优点是结构定型,建立方法
简单,存取方便;缺点是不得更新,插入或
删除时效率低。
动态索引结构优点是在插入或删除时能够自
动调整索引树结构,以保持最佳的搜索效率
缺点是实现算法复杂。
练习
已知一组关键字为 25
{25,18,46,2,53,39,32,4,74,67,60,11} 18 46
。按表中的元素顺序依次插入到
一棵初始为空的二叉排序树中 , 2 39 53

画出该二叉排序树 , 并求在等概 4 32 74
率的情况下查找成功的平均查找
11 67
长度。
60

11  2 2  3  3  3 4  2  5  1 6
ASL   3.5
12
2 、给定数列 {7,16,4,8,20,9,6,18,5} ,构
造一颗二叉排序树。同时给出对应的平衡二
叉排序树。
3 、已知如下所示长度为 12 的表
( Jan,Feb,Mar,Apr,May,June,July,Aug,Sep
,Oct,Nov,Dec )
(1) 试按表中元素的顺序依次插入一棵初始为
空的二叉排序树,画出插入完成之后的二叉
排序树,并求其在等概率的情况下查找成功
的平均查找长度。
(2) 若对表中元素先进行排序构成有序表,求
在等概率的情况下通过折半查找查找成功的
平均查找长度。
(1) 求得的二叉排序树如下图所示,在等概率情
况下查找成功的平均查找长度为:
ASLsucc=1/12(1*1+2*2+3*3+4*3+5*2+6*1)=7/2
(2) 经排序后的表及在
折半查找时找到表中元
素所经比较的次数对照
如下图所示:
在等概率情况下查找成
功的平均查找长度为 :
ASLsucc=1/12(1*1+2*2+
3*4+4*5)=37/12
3 、在地址空间为 0-16 的散列区中,对以下
关键字序列构造两个散列表:
( Jan,Feb,Mar,Apr,May,June,July,Aug,Sep
,Oct,Nov,Dec )
(1) 用线性探测开放定址法处理冲突。
(2) 用链地址法处理。
并分别求这两个散列表在等概率情况下查找
成功的平均查找长度。

(1) 散列表如下图所示,在等概率情况下查找成功
的平均查找长度为:
ASLsucc=1/12(1*5+2*3+4*1+5*2+6*1)=31/12
(2) 散列表如下图所示,在等概率情况下查找成
功的平均查找长度为:
ASLsucc=1/12(1*7+2*4+3*1)=18/12

You might also like