声明:本文内容主要用于408考研复习,主要总结重要知识点和疑难点,文中大部分文字源于参考书籍,仅部分内容为AI生成(已在文中标注),并对部分考研真题的解题方法和思路进行了总结。
参考书籍:《数据结构(C语言版)(第二版)》严蔚敏、李冬梅,《数据结构考研复习指导》王道计算机教育
目录
一、线性表的查找
| / | 顺序查找 | 折半查找 | 分块查找 |
|---|---|---|---|
| 平均查找长度ASL | n + 1 2 \frac{n+1}{2} 2n+1 | n + 1 n log 2 ( n + 1 ) − 1 \frac{n+1}{n}\log_{2}(n+1)-1 nn+1log2(n+1)−1 | ASLbs=Lb+Lw = 1 2 ( n s + s ) + 1 \frac{1}{2}(\frac{n}{s}+s)+1 21(sn+s)+1 = log 2 ( n + 1 ) + s 2 \log_{2}(n+1)+\frac{s}{2} log2(n+1)+2s |
| 时间复杂度 | O(n) | O( log 2 n \log_{2}n log2n) | 优于顺序查找,远不及折半查找 |
| 性能 | 差 | 好 | 优于顺序,远不及折半 |
| 适用结构 | 链式or顺序表 | 有序、数据元素变动较少的顺序表 | 动态变化的线性表 |
| 优点 | 算法简单,对表结构无任何要求 | 比较次数少,查找效率高 | 1.块内无序,因此删除插入容易,无需大量移动; 2.适用于动态变化且需快速查找的线性表 |
| 缺点 | 平均查找长度大,查找效率低 | 1. 仅适用于顺序存储的有序表; 2.插入和删除时,平均比较和移动表中一半的元素,不适用于数据元素经常变动的线性表 | 要增加一个索引表的存储空间,并对初始索引表进行排序 |
题目总结
1.【折半查找判定树】
参考文章(强推👍🏻):快速判断某棵树是否为折半查找判定树(记得看评论区)

- 折半查找二叉树一定是一颗平衡二叉树
- 树的高度为 ⌊log₂n⌋ + 1 或 ⌈log₂(n+1)⌉
- 若关于根节点对称,且非满二叉树,那它一定不是折半查找二叉树
- 当表中元素个数为偶数个时,那么折半所产生的子表中,必然会出现两种情况:
- ①前子表比后子表多一个元素;
- ②后子表比前子表多一个元素;且以这2种结构推其后所有的子表应均满足此结构。
- 当表中元素个数为奇数个时,那么折半所产生的子表中,只会产生一种情况,即前后子表元素个数相同,那么以这种结构推其后所有的子表应均满足此结构。
2.【折半查找序列特点】(二叉排序树的序列特点也是一样)
对于序列中任意数字,后面的要么全比它大,要么全比它小。

二、树表的查找
09-21年之间,选择题几乎必考 二叉排序树 或 平衡二叉树ALV ,一定要掌握平衡二叉树的旋转,注意辨析这两个树。但是22-25已经4年没考了,还是要注意复习。红黑树(本质还是二叉排序树)不怎么考察,对于插入的处理,记住红父红叔、红父黑叔的处理就行,还有3条基本性质大概就够了。
2.1 二叉排序树(内查找法)
1.二叉排序树的定义
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树。
(1)若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
(2)若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
(3)它的左、右子树也分别为二叉排序树(递归性质)。
【特征】
- 中序遍历一棵二叉排序树时可以得到一个节点值递增的有序序列。
- 折半查找为 n 的顺序表的决策树是唯一的,但含有 n 个节点的二叉排序树却不唯一,有 1 n + 1 C n 2 n \frac{1}{n+1}\textrm{C}_{n}^{2n} n+11Cn2n种可能的结构。
- 对于二叉排序树,删除一个叶子节点后,再插入该节点,得到的二叉排序树和原来的一定相同;删除一个分支节点后,再插入该节点,得到的二叉排序树和原来的一定不同。
而对于平衡二叉树无论删除的是非叶节点还是叶子节点,再次插入后都可能和原来的树相同or不同,因为删除和插入都可能导致调整。
2.二叉排序树的删除
若z是被删除节点,且z为:
- 叶节点——直接删除
- 只有左/右子树——让z的子树成为z的父节点的子树
- 有左右子树——令z的直接后继/直接前驱代替z,然后从二叉排序树中删去概直接后继/直接前驱,转换成上面两种情况
3.平均查找长度
与树的形态有关。最坏情况下为插入的关键字有序, A S L = n + 1 2 ASL=\frac{n+1}{2} ASL=2n+1,与顺序查找相同;最好情况下树形态与折半查找的决策树形态相似, A S L ASL ASL 与 log 2 n \log_{2}n log2n 成正比。综合所有情况,其平均查找长度与 log 2 n \log_{2}n log2n 同数量级。
题目小结
【二叉查找树的形态数】
一棵有n个不同元素的二叉查找树有多少种不同形态? ⇌ 含n个结点的二叉树有多少种异构?
答案为卡特兰数
1
n
+
1
C
n
2
n
\frac{1}{n+1}\textrm{C}_{n}^{2n}
n+11Cn2n
2.2 平衡二叉树(ALV树)(内查找法)
1.定义与性质
【定义】
平衡二叉树要么是空树,要么是具有如下特征的二叉排序树:
(1)左子树和右子树的深度之差的绝对值不超过1;
(2)左子树和右子树也是平衡二叉树。
ALV树是一种改进的二叉排序树,因为树的高度越小,查找速度越快。因此在二叉排序树的基础上,通过平衡因子来限制树的高度,从而让二叉排序树的性能得到进一步提升。但是每次增删都可能导致全树拓扑结构的调整(计算不平衡因子、找到最小不平衡树、旋转调整),代价较大,所以平衡二叉树适合查找多但是增删少的场景。
【特点】
1.若将二叉树上节点的平衡因子(Balance Factor,BF)定义为该节点左子树和右子树的深度之差,则平衡二叉树上所有节点的平衡因子只可能是−1、0和1。只要二叉树上有一个节点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。
2.AVL树上任何节点的左右子树的深度之差都不超过1,则可以证明它的深度和 log 2 n \log_{2}n log2n 是同数量级的(其中n为节点个数)。由此,其查找的时间复杂度是 O ( log 2 n ) O(\log_{2}n) O(log2n)。
3.适用于查找为主,增删较少的场景。
2.失衡调整
参考文章(👍🏻强推):二叉平衡(AVL)树中的 LL旋转、RR旋转、LR旋转、RL旋转 的详细解释
另:失衡调整时,每次调整的对象都是最小不平衡子树
题目小结
1.【平衡二叉树的最小深度、最大深度(最少结点数)】
参考文章(强推👍):平衡二叉树的最大深度和最少节点数、推导过程
- 最小深度:n个结点的平衡二叉树深度最小值为 ⌊log₂n⌋ + 1(此时,前 h-1层是满的,只有最下面一层不满,类似于完全二叉树)
- 最大深度:S(h) = S(h-1) + S(h-2) + 1 并且 S0 = 0, S1 = 1(此时,深度为h的平衡二叉树结点数最少,且任一结点左右子树深度都不同,相差1)

PS:往一棵空的平衡二叉树中顺序插入n个节点,若 n = 2 h − 1 n=2^{h}-1 n=2h−1,则插入之后该平衡二叉树的高度为 h(得到满二叉树)
2.【平衡因子】
结点数目一定时,所有非叶结点平衡因子为±1时,树最高。
【2012年统考真题】若平衡二叉树的高度为 6,且所有非叶子结点的平衡因子均为1,则该平衡二叉树的结点总数为()。
A.12
B.20
C.32
D.33
这道题本质上还是在考察最小结点数(最大深度),用S(h) = S(h-1) + S(h-2) + 1 求得20
2.3 红黑树(内查找法)
参考文章:红黑树定义及性质,红黑树的插入删除
注:红黑树几乎不怎么考察,如果实在难以理解插入过程,就记一记基本概念就行,也确实比较难
【特性】
1.节点是红色或黑色
2.根是黑色
3.叶子节点(虚构的外部节点,NULL节点)都是黑色
4.不存在 2 个连续的红色节点(即红节点的父节点、孩子节点都是黑色的)
5.从任一节点到叶子节点的所有路径都包含相同数目的黑色节点
【结论】
1.从根到叶节点的最长路径不大于最短路径的 2 倍
- 当根到任意一个叶节点的简单路径最短时,该路径必然全由黑节点构成;
- 当某条路径最长时,必然由红黑节点相间构成的,此时红节点和黑节点数量相同;
- 红色结点数目最大可以是黑色结点数目的2倍(比如3个结点时)
2.有n个内部节点的红黑树的高度 h ≤ 2 log 2 ( n + 1 ) h ≤ 2\log_{2}(n+1) h≤2log2(n+1)
红黑树降低了动态操作时调整的频率,由ALV树的“高度平衡”降低到“任意一个节点左右子树的高度,相差不过2倍”。因此对于查找多、增删少的用ALV树较合适;增删多、查找较少的用红黑树更合适。
红黑树的查找,插入和删除操作,时间复杂度都是O(logN)。
【查找操作】红黑树与相对平衡的二叉搜索树的效率相同,二者通过相同的方式查找,并未体现红黑树的特性。但插入有序数据时,红黑树的查询效率则高于二叉搜索树。
【插入和删除操作】红黑树的每次操作平均要旋转一次和变换颜色,因此比普通的二叉搜索树效率更低,但时间复杂度仍为 O ( l o g 2 N ) O(log_{2}N) O(log2N)。
3.新插入红黑树的节点初始为红色
如果插入的节点是红色,此时所有路径上的黑色节点数量不变,仅可能会出现两个连续的红色节点的情况。这种情况下,通过变色和旋转进行调整即可。
插入流程如下:
红父黑叔——旋转(同平衡二叉树的旋转)+染色(旋转互换的对象)
红父红叔——(叔父爷)染色+变新(爷视为新插入节点)

2.4 B树(外查找法)
【定义】
一棵 m 阶的B树,或为空树,或为满足下列特性的m叉树:
(1)树中每个节点至多有 m 棵子树;
(2)若根节点不是叶子节点,则至少有1个关键字,2棵子树;
(3)除根之外的所有非终端节点 至少 有 ⌈m/2⌉ 棵子树, ⌈m/2⌉-1 个关键字;
(4)所有的叶子节点都出现在同一层次上,并且不带信息,通常称为失败节点(失败节点并不存在,指向这些节点的指针为空。引入失败节点是为了便于分析B−树的查找性能);
(5)所有的非终端节点 至多 有 m − 1 个关键字

m 阶 B 树其实也是所有结点的平衡因子均等于 0 的 m 路平衡查找树。
【插入】
1)插入:根据要插入的key的值,找到叶子结点并插入。
2)判断:判断当前结点key的个数是否小于等于m-1,若满足则结束,否则进行第3步。
3)分裂:以结点中间的key为中心分裂成左右两部分,然后将这个中间的key插入到父结点中,这个key的左子树指向分裂后的左半部分,这个key的右子支指向分裂后的右半部分,然后将当前结点指向父结点,继续进行第3步。
【删除】(较难)
- 非叶子节点删除:替换为前驱节点或后继节点,然后删除原位置的前驱或后继节点(转换为叶子节点的删除)

- 叶子节点的删除:
- 删除前关键字大于⌈m/2⌉,直接删除
- 删除前关键字小于⌈m/2⌉:
- 兄弟够借:调整该节点、左/右兄弟和双亲节点,以达到新平衡
- 兄弟不够借:将关键字删除后,与左(或右)兄弟及双亲节点中的关键字合并

题目小结
【B树关键字个数、结点个数/高度问题】
对于一颗有 N 个关键字的B树,计算的时候,
①算出至少(⌈m/2⌉-1)和至多(m-1)每个结点内的关键字个数 k-1;注意不论几阶B树,根节点关键字最少是1(特殊性)
②每个结点(根节点除外)至少有几棵子树 k(至少⌈m/2⌉,至多 m)
③非根的总结点个数
n
−
1
=
⌈
N
−
1
k
⌉
n-1=\left\lceil{\frac{N-1}{k}}\right\rceil
n−1=⌈kN−1⌉,总结点个数 n(N-1是减去根节点后的总节点个数)
④画出第1、2层(不然计算容易出错)
⑤对于最高的树,从第二层开始,转化为总结点个数为 n 的 m 叉树问题,计算公式
1
+
2
[
k
0
+
k
1
+
k
2
+
…
…
+
k
h
′
]
≥
n
1+2[k^{0}+k^{1}+k^{2}+……+k^{h'}]≥n
1+2[k0+k1+k2+……+kh′]≥n,最终高度
h
=
h
′
+
1
h= h'+1
h=h′+1(树最高的情况下,根节点关键字只有一个,所以第二层一定有且仅有2课子树)
对于最矮的树,直接转化为总结点个数为 n 的 m 叉树问题,计算公式
k
0
+
k
1
+
k
2
+
…
…
+
k
h
≥
n
k^{0}+k^{1}+k^{2}+……+k^{h}≥n
k0+k1+k2+……+kh≥n,最终高度
h
h
h
【例题】一棵5阶B树中含有53个关键字,则该树的最大深度为(),最小深度为()
A.2 B.3 C.4 D.5
【解析】树高越高,每个结点(根节点除外)关键字越少,结点数越多;反之,结点数最少时,可使树最矮。此题中m为5:
| / | 至少 | 至多 |
|---|---|---|
| 根结点关键字 | 1 | m-1=4 |
| 其余结点关键字 k − 1 k-1 k−1 | ⌈m/2⌉-1=2 | m-1=4 |
| 作图 | ![]() | ![]() |
| 计算结点个数 n n n | ⌈ 53 − 1 2 ⌉ + 1 = 27 \left\lceil{\frac{53-1}{2}}\right\rceil+1=27 ⌈253−1⌉+1=27 | ⌈ 53 4 ⌉ = 13 \left\lceil{\frac{53}{4}}\right\rceil=13 ⌈453⌉=13 |
| 计算高度 h h h |
1
+
2
[
3
0
+
3
1
+
3
2
+
…
…
+
3
h
′
]
≥
n
1+2[3^{0}+3^{1}+3^{2}+……+3^{h'}]≥n
1+2[30+31+32+……+3h′]≥n h = h ′ + 1 = 4 h=h'+1=4 h=h′+1=4 |
5
0
+
5
1
+
5
2
+
…
…
+
5
h
≥
n
5^{0}+5^{1}+5^{2}+……+5^{h}≥n
50+51+52+……+5h≥n h = 3 h=3 h=3 |
2.5 B+树(掌握概念、区别、应用场景即可)
一棵 m 阶的 B+树和 m 阶的B树的差异在于:
(1)有 n 棵子树的节点中含有 n 个关键字;
(2)所有的叶子节点中包含了全部关键字的信息,以及指向含这些关键字记录的指针,且叶子节点本身依关键字的大小自小而大顺序链接;
(3)所有的非终端节点可以看成索引部分,节点中仅含有其子树(根节点)中的最大(或最小)关键字。
换句话说就是:
(1)B树的每个节点都存储数据,而B+树只有叶子节点存储数据。
(2)B树的搜索性能不固定,而B+树的搜索性能固定为O(log n)。因为,在B+树中,不管查找成功与否,每次查找都走一条从根到叶子节点的路径。
(3)B+树由于内部节点不存储数据,每个节点能索引的范围更大,因此在磁盘I/O上表现更好,减少了磁盘I/O次数。
(4)B+树的叶子节点形成有序链表,适合进行范围查询,而B树不支持这样的操作。
B+树适合于需要频繁进行插入和删除操作的场景,如数据库索引、文件系统。
例如,下图所示为一棵3阶的B+ 树,通常在B+ 树上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点。因此,可以对B+ 树进行两种查找运算:一种是从最小关键字起顺序查找;另一种是从根节点开始,进行随机查找。

三、散列(Hash)表的查找
参考文章:Hash表
常考:1)除留余数法(构造Hash函数);2) 线性探测法(解决冲突)
3.1 散列函数的构造方法
-
数字分析法: 如果事先知道关键字集合,且每个关键字的位数比散列表的地址码位数多,则可以从关键字中提取数字分布比较均匀的若干位作为散列地址。
-
平方取中法: 如果关键字的每一位都有某些数字重复出现频率很高的现象,可以先求关键字的平方值,通过平方扩大差异,而后取中间数位作为最终存储地址。
-
折叠法: 如果数字的位数很多,可以将数字分割为几个部分,取他们的叠加和作为hash地址。适用于数字位数较多且事先不知道数据分布的情况。
-
除留余数法(常考): H(key) = key%p,i 为冲突次数,初始为0
3.2 处理冲突的方法
1.开放地址法
- 线性探测法(常考):可能导致大量元素堆积,降低查找效率
- 平方探测法: 散列表长度 m 必须是一个可以表示成 4k+3 的素数(否则只能探测到散链表中一半的位置,剩余的空位无法被探测到并插入)
- 双散列法: di = i×Hash2(key)%m
- 伪随机序列法
删除元素: 采用开放定址法时,不能随便删除表中已有元素,否则会截断其他同义词的查找路径。要删除时,一般有2种处理方法,没有特别声明的情况下,一般采用逻辑删除法(DEL标记)(实际中使用也更广泛)。
- 惰性删除(逻辑删除)法: 将被删除的单元标记为特殊的“已删除”标记 DEL(而不是 NULL/空)。查找时,遇到 DEL 标记继续探查;插入时,遇到 DEL 标记可以覆盖。(PS这一段不是来源于具体的书籍资料,因为严蔚敏老师书上和王道书上都没找到关于逻辑删除法特别清楚的解释,所以是用GPT生成的。)
- 真删除(物理删除)并移动元素: 找到被删除元素后面的一串连续元素,对每一个元素重新计算其初始地址,如果它的初始地址在被删除位置之前,则移动它以填补空位,直到遇到 NULL 或 DEL。
2.链地址法
把具有相同散列地址的记录放在同一个单链表中,称之为同义词链表。有m个散列地址就有m个单链表,同时用数组HT[0…m−1]存放各个链表的头指针,凡是散列地址为 i 的记录都以节点方式插入以HT[i]为头节点的单链表。
3.3 散列查找及性能分析(小考点,记一记)
- 影响散列查找效率的因素 :散列函数、处理冲突的方法、装填因子α

- 查找成功 的平均长度是针对 表中所有存在的关键字(DEL不算)的查找探查次数的平均值。
- 查找失败 时的情况有两种(总结就是,直到找到 NULL 空单元,若没有空单元 NULL 则要将整个散列表探测一遍,才确认查找失败。PS关于查找失败的定义,括号里的都是我自己的个人理解,方便整理思路,其余文字都是严蔚敏老师《数据结构(C语言版)(第二版)》的原话):
(1)单元为 空 (NULL);
(2)按处理冲突的方法探测一遍后仍未找到。假设 0 ~ r-1 相当于 r 个查找失败的入口,从每个入口进入后,直到确定查找失败(即找到空单元,NULL,或探测完一整个散列表)为止,其关键字的比较次数就是与该入口对应的查找失败的查找长度。
题目小结
【失败的查找长度】
参考文章:散列表查找失败平均查找长度(一位暴躁但讲很清楚的博主hhh)
【2019年统考真题】现有长度为11且初始为空的散列表 HT,散列函数是 H(key)=key %7,采用线性探查(线性探测再散列)法解决冲突。将关键字序列87,40,30,6,11,22,98,20依次插入 HT后,HT 查找失败的平均查找长度是______。
【解析】先将关键字存放进散列(下表前2行):
| 散列地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 关键字 | 98 | 22 | 30 | 87 | 11 | 40 | 6 | 20 | |||
| 查找失败次数 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 散列函数无法探测到 | |||
由于 H(key)=0~6(7个查找入口),因此查找失败时可能对应的地址有7个。对于用散列函数计算出地址为 0 的关键字key0,只有比较完 0 ~8 号地址后,才能确定该关键字不在表中,比较次数为9;对于计算出地址为 1 的关键字,只有比较完 1 ~8 号地址后,才能确定该关键字不在表中,比较次数为8;以此类推。而由于用散列函数只能算出 0 ~ 6,所以不可能算出地址 7 及以后的位置(不在查找入口范围内),7 ~10 只有在前面都冲突时才会被探测到。ASL 失败 = (9+8+7+6+5+4+3)/ 7 = 6
2.【线性探测法删除】
❗【2023年统考真题】 现有长度为5,初始为空的散列表HT,散列函数H(k)=(k+4)%5,用线性探查再散列法解决冲突。若将关键字序列 2022,12,25 依次插入HT,然后删除关键字25,则HT中查找失败的平均长度为______。
【解析】先将关键字放入散列表(下表前2行):
| 散列地址 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 关键字 | 2022 | 12 | 25(DEL) | ||
| 查找失败次数 | 1 | 3 | 2 | 1 | 2 |
易错点来了(其实就是3.2和3.3的红字部分),很多小伙伴会奇怪为什么散列地址 4 对应的查找失败次数是 2。原因在于,遇到 DEL 标志必须向下探查,直到查找成功或遇到 NULL(没有NULL则需要把整个表探测一遍)。因此,当探测地址4的时候,4中是DEL,所以要继续取模探测(因为是取模,所以不会导致越界访问,而是形成了一个逻辑上的环形结构)。因此回到位置 0,0恰好是NULL,判定查找失败,因此查找失败次数为2。
【举一反三】在一个长度为4的空散列表中依次插入2,3,1,4,散列函数为H(k)=key%4,用线性探查再散列法解决冲突,然后删除3,查找失败的平均查找长度是_____,查找成功的平均查找长度是______。(这道题如果觉得有问题,欢迎在评论区讨论)
【解析】插入后散列表为(4,1,2,3),再删除3,此时散列表为(4,1,2,DEL),表中没有空(NULL),因此对于每个元素都要查询4次,查找失败的平均查找长度是4。查找成功的平均长度是1,查找成功只针对表中存在的元素,DEL不算,所以是(1+1+1)/ 3 = 1。


1万+

被折叠的 条评论
为什么被折叠?



