通用数据结构 II——索引结构(在数据之上建立搜索路径)

7 阅读7分钟

第二章:通用数据结构 II——索引结构(在数据之上建立搜索路径)

绪论:从存储问题到定位问题

  • 第一章解决的问题是:数据如何存放
  • 但存储方式只能决定“放在哪里” ,并不能解决“如何快速找到”。

当数据规模扩大时,如果查找仍依赖遍历:

  • 访问成本保持在 O(n)
  • 并随数据规模 线性增长

因此系统需要一种新的结构,使查找过程不再检查全部数据,而是:

逐步缩小可能的搜索范围。

这种用于组织查找路径的结构,被称为:

索引结构

  • **定义:**索引结构是在既有存储结构之上建立 搜索路径,从而在查找过程中 逐步压缩搜索空间

  • **基本模型:**根据索引与数据之间的关系,索引结构可以归纳为两种基本模型:

    1. 外部索引:在原有存储结构之外建立独立的定位层
    2. 内部索引:在数据结构内部组织查找路径

一、外部索引模型:存储与定位分离

定义

  • 外部索引将 数据存储数据定位 分离。
  • 数据保存在主结构中,同时维护一套独立的 Key → Address 映射结构。

机制

  • 结构:系统维护两套结构:

    1. **主结构:**负责存储数据
    2. 索引结构:负责定位数据
  • 查找流程:

    1. 通过索引结构定位目标位置
    2. 根据定位结果回到主结构读取数据

特征

  • 主结构保持稳定
  • 索引层可独立扩展,查找能力可单独增强
  • 索引结构需要额外存储空间
  • 更新操作需要同步维护索引

范围说明

  • 外部索引描述的是一种 结构组织方式
  • 具体索引形态通常高度依赖系统场景,因此在此只给出抽象模型,后续在具体系统设计中展开。

总结

  • 外部索引通过 独立定位结构 提升查找效率,同时保持主结构不变。
  • 该模型在数据库与存储系统中非常常见。

二、内部索引模型:将查找嵌入结构

定义

  • 与外部索引不同,内部索引不建立独立定位层,而是 直接改变数据组织方式

机制

  • 查找路径被嵌入结构内部:

    • 数据组织方式决定查找过程
    • 查找路径成为结构的一部分

结构原则:压缩搜索空间

  • 内部索引的核心目标是:通过结构组织压缩搜索空间

  • 本质问题是:

    如何在查找过程中尽可能减少需要访问的数据范围。

  • 不同结构通过不同方式实现这一目标。

组织方式:三类压缩路径

  • 根据压缩搜索空间的方式不同,内部索引可以归纳为三类结构:

    1. 有序索引
    2. 分层索引
    3. 分块索引

三、有序索引

  • 有序索引通过 保持数据整体有序,使查找范围不断缩小。
  • 核心思想是:通过顺序关系压缩搜索空间,二分查找是最典型实现。

A. 有序数组

定义

  • 数据按键值顺序存储在连续数组中。

机制

  • 查找通过 二分查找 实现,每次比较缩小一半搜索空间。

特征

  • 查找复杂度:O(log n)
  • 更新复杂度:O(n)
  • 连续存储,缓存局部性好

总结

  • 有序数组通过 全局有序 + 二分查找 提供 O(log n) 查找能力。
  • 更新成本高,更适合 静态数据集合
  • 在工程实践中,有序数组常用于数据规模稳定、更新较少的场景(如只读索引、静态查找表)

B. 树结构(平衡搜索树)

定义

  • 二分查找思想 固化为树形结构。

机制

  • 结构

    • 每个节点包含左右指针
    • 左子树键值小于当前节点,右子树键值大于当前节点
    • 保持全局有序
  • 查找流程:

    1. 从根结点开始比较
    2. 沿分支向下,小于进入左子树
    3. 查找路径长度等于 树高。
  • 更新流程:

    • 插入 按有序规则 找到位置
    • 删除时用前驱/后继替换
    • 为避免退化,通过旋转保持树高在 O(log n)

特征

  • 查找复杂度:O(log n)
  • 更新复杂度:O(log n)
  • 为保持平衡,需要结构维护(旋转)
  • 节点间通过指针连接,缓存局部性弱于连续结构

总结

  • 平衡搜索树通过 有序结构 + 受控树高 提供稳定的 O(log n) 查找与更新能力。
  • 这种结构将 二分查找思想 扩展到动态数据集合,但也因此引入了结构维护成本
  • 在工程实践中,树结构常通过 减少指针跳转、增强局部连续性 等方式优化缓存表现。

四、分层索引

  • 分层索引通过 建立多级索引层,跨越更大的数据区间,再逐层逼近目标。

跳表

定义

  • 在有序链表之上构建 多级索引层,将线性遍历转化为分层跳跃

机制

  • 结构:

    • 底层:完整有序链表,存储全部元素
    • 高层:稀疏索引链表,用于跨区间跳跃
  • 查找流程:

    1. 从最高层横向移动
    2. 无法继续前进时下降一层
    3. 最终在底层完成精确定位
  • 更新流程:

    • 插入:在底层插入,并随机决定节点层数
    • 删除:同时移除各层索引节点

特征

  • 查找/插入/删除:平均 O(log n)
  • 用概率平衡替代严格平衡,维护成本低
  • 指针离散,缓存局部性弱于数组

总结

  • 跳表通过 分层索引 → 跨区间跳跃 → 逐层逼近,将链表查找从 O(n) 降到平均 O(log n)
  • 相比平衡树,它以 概率平衡 替代 严格平衡,结构更简单。
  • 在工程实践中,跳表常用于内存型有序索引结构(如 Redis Sorted Set),其结构简单、更新成本低,并且易于支持并发访问。

五、分块索引

  • 分块索引通过 局部连续存储 减少指针跳转,并在块内进行局部搜索。

块状结构

定义

  • 在链表结构中引入 局部连续存储:每个节点内部维护一个小数组(块)。

机制

  • 结构:

    • 块内:为一个连续数组,存储多个元素
    • 块间:通过指针连接
  • 结构:先沿链表定位目标块,再在块内顺序或二分查找。

  • 更新流程:

    • 插入/删除发生在块内,需移动块内元素
    • 块满触发分裂,块空触发合并
    • 维护集中在块级别

特征

  • 查找复杂度:O(n / B + log B)(B 为块大小)
  • 插入/删除复杂度:通常为 O(B)
  • 块大小通常控制在合适范围,以平衡访问与维护成本。
  • 块内连续提升缓存命中率
  • 指针跳转次数明显减少

总结

  • 块状结构通过 块内连续 + 块间链接,在数组局部性与链表灵活性之间取得工程折中。
  • 本质上是一种 链表块化的工程优化
  • 在工程实践中,块状链表常以“分块 / 分段容器”的形式出现,通过块内连续存储提升遍历与缓存效率,同时保留块间链接带来的扩展与局部修改能力。

本章总结

  • 第一章解决的是:数据如何存放

  • 本章解决的是:如何通过结构组织减少查找范围

  • 为此系统在存储结构之上建立 索引结构,通过搜索路径逐步压缩搜索空间。

  • 内部索引常见三类压缩路径:

    1. 有序索引:保持有序,通过比较缩小范围
    2. 分层索引:多级路径跨区间跳跃
    3. 分块索引:局部连续减少跳转,块内局部搜索
  • 这些结构的共同特点是:查找仍需要沿搜索路径逐步比较。

下一问题

  • 索引结构通过搜索路径压缩搜索空间,但查找仍依赖逐层比较。

  • 是否存在一种结构,可以通过 计算 直接确定数据位置,从而绕开搜索路径?

    下一章讨论:映射结构