查找
查找
核心定义
查找 是在 查找表 中确定指定关键字所在位置的过程。查找题的本质不是”有没有这个值”,而是 用什么方法更快定位。
顺序查找 从表的一端逐个比较,适合 无序表 或规模较小的数据,时间复杂度 O(n),前提条件最少。顺序查找的 平均查找长度(ASL)为 2n+1。
折半查找(二分查找)适合 有序顺序表,利用中点不断缩小范围,时间复杂度 O(logn)。前提是必须能 随机访问中点。折半查找的判定树是 平衡二叉树,树高约 ⌊log2n⌋+1。
二叉排序树查找 利用 左小右大 的结构性质,平均 O(logn),但退化成单链表时查找退化为 O(n)。为避免退化可使用 平衡二叉树(AVL),保证左右子树高度差不超过 1。
散列查找 利用 哈希函数 把关键字映射到 存储地址,理想情况下查找时间 O(1)。平均性能与 装填因子 α 和冲突程度有关。常用冲突处理方法:拉链法(每个地址维护一个 链表)和 开放定址法(遇到冲突时 找下一个空位,包括线性探测、二次探测等)。
分块查找 将表分成若干块,块间 有序、块内 无序,先确定块再在块内顺序查找。索引表的作用是快速定位到目标块,因此分块查找也称为 索引顺序查找。
考研重点:前提条件、平均性能、最坏情况、冲突处理。若在 1024 个有序元素中查一个值,折半查找大约只需 10 次比较(log21024=10)。
B树 是一种 多路平衡查找树,常用于 磁盘等外存 中的索引结构,所有查找路径长度相同。B+树 的所有数据都在 叶子结点,且叶子结点用 链表串联,支持范围查询。
查找方法选择决策表(按数据特征 + 需求定位):
| 数据特征 / 需求 | 选用方法 | 性能 / 前提 |
|---|---|---|
| 无序 | 顺序查找 | O(n),无前提 |
| 有序 + 顺序表(可随机访问) | 折半查找 | O(logn) |
| 有序 + 链表(不能随机访问) | 顺序查找 | O(n)(折半不可用) |
| 要求平均最快 | 散列查找 | 平均 O(1),关注冲突处理 |
| BST(左小右大) | 二叉排序树查找 | 平均 O(logn),退化 O(n) |
| AVL(平衡保证) | 平衡二叉树查找 | 始终 O(logn) |
| 外存索引 | B 树 / B+ 树 | 多路平衡,B+ 树叶子链表支持范围查询 |
关键细节 / 操作步骤
方法选型(看数据特征选方法)
- 先判断数据是否 有序。
- 若有序且可随机访问,优先考虑 折半查找。
- 若是树形结构,检查是否为 二叉排序树(BST),并判断插入顺序是否会 退化成链表。
- 若题目要求平均更快,考虑 散列查找。
- 若题目要求结构最简单,考虑 顺序查找——无需预处理,无需额外空间。顺序查找的哨兵机制可以 省去越界判断。
- 若题目让你选方法,先问自己:是否有序、是否能随机访问、是否允许辅助结构。
前提与陷阱
- 若涉及折半查找,先确认是否能直接通过 下标访问中点。
- 若涉及散列,先看 冲突处理方法(拉链法 vs 开放定址法),再计算 ASL。
- 查找题中最容易忽略的是 前提条件,不是公式本身。
复杂度与 ASL
- 若题目问复杂度,先区分 最好、平均、最坏 三个层次。
- 若题目给成功和失败查找长度,要分别分析 命中 与 未命中 的路径长度。
- 若题目问散列表的装填因子 α,定义为 表长元素个数,α 越大冲突越严重。
- 若题目问折半查找的判定树,它是 近似平衡 的二叉树,失败结点(外部结点)共 n+1 个。
- 若题目问散列表查找成功 ASL,核心是 各关键字比较次数之和除以关键字个数。
冲突处理与 B 树
- 若题目问开放定址法中线性探测的缺点,核心是 堆积现象(聚集导致冲突连锁)。
- 若题目问开放定址法中二次探测的公式,探测序列为 (H(k)+di)%m,其中 di 为 12,−12,22,−22,…。
- 若题目问 B 树的阶数 m,每个结点最多有 m 个子树、m−1 个关键字,最少有 ⌈m/2⌉ 个子树。
⚠️ 易错辨析 折半查找要求有序,不能在无序表上直接用——真题常拿”能减半”误写成”随便什么表都能减半”。散列查找平均快不代表最坏情况也快,发生大量冲突时性能可能显著下降。二叉排序树查找的效率依赖树形是否平衡,退化成单链表时查找退化为 O(n)。顺序查找虽然慢但前提最少,常用于无序或缺少辅助结构的场景。反例:对链表做折半查找是错误的,因为链表不能随机访问中点。开放定址法中 删除操作 需要特殊标记(如懒删除),否则会影响后续查找。
💡 技巧与口诀 口诀:无序顺序扫,有序二分找,树形看 BST,平均更快看散列。适用场景:看到”有序""顺序存储""中点”就先想折半查找;看到”哈希地址""冲突”就先想散列。若题目只给一张表,先从”是否有序”开始筛选查找方法。散列表 ASL 计算时,成功查找是 各元素比较次数的平均,失败查找是 各位置到空位的比较次数的平均。
📝 真题闭环 题目:对含有 n 个元素的有序顺序表,折半查找的平均查找长度(ASL)大约是多少?若查找成功和查找失败分别分析,哪个更大?
解题思路:审题抓”有序顺序表”和”平均查找长度”,切入点是 折半查找;方法选择为判定树分析;计算关键点是判定树近似平衡,树高约 ⌊log2n⌋+1,每层比较次数等于该层深度;易错防范是把链表当顺序表做折半。
答案:折半查找成功 ASL 约为 log2(n+1)−1,失败查找长度通常比成功 略大,因为失败对应判定树的 外部结点路径。
// T=O(log n) S=O(1)
int binary_search(int a[], int n, int x) {
int l = 0, r = n - 1;
while (l <= r) {
int m = l + (r - l) / 2;
if (a[m] == x) return m;
else if (a[m] < x) l = m + 1;
else r = m - 1;
}
return -1;
} cd ..