Professional Documents
Culture Documents
教学内容
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
查找成功
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
查找失败
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 内结点
例如: 顺序表
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 最大 最小 两者之间
中序遍历二叉排序 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≤m1)
插入前结点中关键字个数 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 608090
60
80
90
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 树——插入操作
18 33
12 23 30 48
10 15 20 21 24 31 45 47 50 52
55
2 – 3 树——插入操作
18 33
12 23 30 48
10 15 20 21 24 31 45 47 50 52 55
插入
2 – 3 树——插入操作
18 33
12 23 30 48
10 15 20 21 24 31 45 47 50 52 55
分裂
2 – 3 树——插入操作
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
冲突是不可能避免的,可通过构造好的哈希函数
减少冲突;还需要找到“处理冲突”的方法
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²(km/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
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
11 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