首页/数据结构/06-search/分块查找 🔗 在 Obsidian 中打开
数据结构 · 06-search

分块查找

难度 ★★★重要度 ★★ 考查频率 低题型 选择 / 计算 分块查找索引顺序查找
速查
分块查找(索引顺序查找)是顺序查找与折半查找之间的方法:表分块、块内无序、块间有序,建立索引表。ASL ≈ $\sqrt n + 1$(最优分块 $b=s=\sqrt n$)。

速查

项目
主题分块查找
核心概念分块查找是介于顺序查找和折半查找之间的查找方法
时间复杂度$O(\sqrt n)$(最优分块时)
结构特点块间有序、块内无序
难度⭐⭐⭐

核心概念

分块查找(Blocking Search / Index Sequential Search)是介于顺序查找折半查找之间的一种查找方法。

基本思想

  1. 将表分成若干块(Block)
  2. 块内可以无序
  3. 块间必须有序(第 i 块的最大值 < 第 i+1 块的最小值)
  4. 建立索引表,记录每块的最大关键字和起始地址

存储结构

// 索引表项
typedef struct {
    IndexType maxValue;  // 块内最大关键字
    int start;           // 块的起始位置
    int length;          // 块的长度
} IndexItem;

// 主表 + 索引表
IndexItem index[MAX_BLOCKS];  // 索引表
ElemType data[MAX_SIZE];       // 主表

图示

索引表:
┌─────────────────────────────────┐
│ maxValue=25, start=0, length=5  │  块1
│ maxValue=50, start=5, length=5  │  块2
│ maxValue=75, start=10, length=5 │  块3
└─────────────────────────────────┘

主表(块内无序,块间有序):
块1: [22, 13, 25, 8, 17]    块1最大值=25
块2: [45, 32, 50, 38, 41]   块2最大值=50
块3: [63, 75, 58, 70, 66]   块3最大值=75

关键性质

查找过程

  1. 在索引表中查找:确定目标可能在哪一块
    • 索引表是有序的,可以顺序查找折半查找
  2. 在块内查找:在对应块中顺序查找
    • 块内无序,只能顺序查找

时间复杂度

假设 n 个元素分成 b 块,每块 s 个元素($n = b \times s$):

索引表用顺序查找

  • 索引表查找:$O(b)$
  • 块内查找:$O(s)$
  • 总时间:$O(b + s)$
  • 当 $s = \sqrt n$ 时,$b = \sqrt n$,总时间为 $O(\sqrt n)$

索引表用折半查找

  • 索引表查找:$O(\log_2 b)$
  • 块内查找:$O(s)$
  • 总时间:$O(\log_2 b + s)$

平均查找长度(ASL)

索引表顺序查找 + 块内顺序查找

$$ASL = \frac{b+1}{2} + \frac{s+1}{2} = \frac{b+s}{2} + 1$$

当 $b = s = \sqrt n$ 时:

$$ASL = \sqrt n + 1$$

索引表折半查找 + 块内顺序查找

$$ASL \approx \log_2(b+1) - 1 + \frac{s+1}{2}$$

手算示例

示例一:计算 ASL

有 16 个元素,分成 4 块,每块 4 个元素。用顺序查找做索引查找,求 ASL。

  • 索引表 ASL:$(4+1)/2 = 2.5$
  • 块内 ASL:$(4+1)/2 = 2.5$
  • 总 ASL:$2.5 + 2.5 = 5$

示例二:最优分块

有 100 个元素,如何分块使 ASL 最小(索引表顺序查找)?

分析:$ASL = b/2 + s/2 + 1$,约束条件 $b \times s = 100$。

用均值不等式:$b + s \geq 2\sqrt{bs} = 2\sqrt{100} = 20$。

当 $b = s = 10$ 时取等号,此时 ASL = $10/2 + 10/2 + 1 = 11$。

示例三:分块查找过程

在上面的示例表中查找 58。

1. 查索引表:
   - 25 < 58,继续
   - 50 < 58,继续
   - 75 ≥ 58,在块 3 中
2. 在块 3 [63, 75, 58, 70, 66] 中顺序查找:
   - 63 ≠ 58
   - 75 ≠ 58
   - 58 = 58,找到!
比较次数:索引表 3 次 + 块内 3 次 = 6 次

示例四:索引表折半查找

索引表有 7 项,用折半查找确定块号,然后在块内顺序查找(块大小 8),求最坏情况比较次数。

  • 折半查找最坏:$\lfloor\log_2 7\rfloor + 1 = 3$ 次
  • 块内顺序查找最坏:8 次
  • 最坏总比较次数:$3 + 8 = 11$ 次

常见考法

题型一:计算 ASL给定元素数和分块方式,求平均查找长度。
题型二:最优分块策略如何分块使 ASL 最小。
题型三:查找过程模拟给定数据和目标值,模拟分块查找过程。
题型四:与其他查找算法对比分块查找与顺序查找、折半查找的性能对比。

易错点

注意
  1. 块间有序,块内可以无序:这是分块查找的前提条件。
  2. ASL = 索引表 ASL + 块内 ASL:两个阶段的查找长度相加。
  3. 最优分块是 $b = s = \sqrt n$:不是平均分就行。
  4. 索引表可以用折半查找:这会进一步减少 ASL。
  5. 分块查找的 ASL 介于顺序和折半之间:$O(\sqrt n)$ 介于 $O(n)$ 和 $O(\log n)$。

核心结论

查找方式时间复杂度ASL适用场景
顺序查找$O(n)$$(n+1)/2$无序表
分块查找$O(\sqrt n)$$\sqrt n + 1$块间有序
折半查找$O(\log n)$$\approx\log_2 n$完全有序

核心公式

  • 最优分块:$b = s = \sqrt n$,ASL = $\sqrt n + 1$
  • $ASL = (b+1)/2 + (s+1)/2$(索引顺序 + 块内顺序)

记忆卡片

分块查找的基本条件?
块间有序,块内可以无序。每块的最大关键字小于下一块的最小关键字。
分块查找的两个阶段?
1) 在索引表中确定目标所在块;2) 在块内顺序查找。
如何分块使 ASL 最小?
$b = s = \sqrt n$(块数 = 每块大小 = 总元素数的平方根),此时 $ASL = \sqrt n + 1$。
分块查找的 ASL 与顺序、折半相比?
介于两者之间。顺序 $O(n)$ > 分块 $O(\sqrt n)$ > 折半 $O(\log n)$。
索引表用折半查找时 ASL 如何算?
$ASL \approx \log_2(b+1) - 1 + (s+1)/2$,即折半查找索引表 + 顺序查找块内。
块内为什么只能顺序查找?
块内无序,无法用折半等方法,只能顺序扫描。

交互动画 · 分块查找

索引表(块最大值):块1=25,块2=50,块3=75;主表每块 5 个元素。查找 58 块1 max=25 块2 max=50 块3 max=75 ↑ 索引表 22 13 25 8 17 块1 45 32 50 38 41 块2 63 75 58 70 66 块3 点「下一步」:先扫索引表定位块,再在块内顺序查找
点击开始:分块查找 58
点「下一步」或「播放」

相关知识点

sequential-and-binary-search hash-table b-tree b-plus-tree search-algorithm-comparison

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。