第七章查找

1. 查找的基本概念

  1. 适合静态查找表的查找方法有顺序查找,折半查找和散列查找等;适合动态查找表的查找方法有二叉排序树的查找和散列查找等

  2. 平均查找长度(ASL): ASL是衡量查找算法效率的最主要指标,指的是所有查找过程中进行关键字的比较次数的平均值.

2. 顺序查找和折半查找

2.1 顺序查找

  1. 顺序查找也称线性查找,它对顺序表和链表是通用的.

  2. 顺序查找的缺点:当n较大时,平均查找长度较大,效率低.

  3. 顺序查找的优点:对数据元素的存储没有要求,顺序存储或链式存储均可.对表中记录的有序性也没有要求.

2.2 折半查找

  1. 折半查找需要方便地定位查找区域,所以它要求线性表必须具有随机存取的特性. 因此不适合于链式存储结构

2.3 分块查找

  1. 分块查找也成为索引顺序查找,吸取了顺序查找和折半查找各自的优点

  2. 分块查找的基本思想: 将查找表分为若干子块.块内的元素可以无序,但块间的元素是有序的.建立一个索引表,索引表中的每个元素含有各块的最大关键字和各块中的第一个元素的地址,索引表按关键字有序排列.

  3. 分块查找的过程分为两步: 第一步是在索引表中确定待查记录所在的块,可以顺序查找或者折半查找索引表;第二步是在块内顺序查找.

3. 树形查找

3.1 二叉排序树(BST)

  1. 二叉排序树(二叉查找树)或者是一棵空树或者具有下列性质:
    (1) 若左子树非空,则左子树上所有结点的值均小于根节点的值
    (2) 若右子树非空,则右子树上所有结点的值均大于根节点的值
    (3) 左右子树也分别是二叉排序树

  2. 二叉查找树由于存在退化成链表的可能性,会使得查询操作的时间复杂度从 O(logn) 升为 O(n)。
    而且会随着插入的元素越多,树的高度也变高,意味着需要磁盘 IO 操作的次数就越多,这样导致查询性能严重下降,再加上不能范围查询,所以不适合作为数据库的索引结构

3.2 平衡二叉树

  1. 平衡二叉树(AVL树)的定义: 或是一颗空树,或是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的高度差的绝对值不超过1.
  2. 定义结点左子树与右子树的高度差为该节点的平衡因子,则平衡因子的值只可能是0,1,-1

4. B 树和B+树

4.1 B树

  1. 为了解决降低树的高度的问题,后面就出来了 B 树,它不再限制一个节点就只能有 2 个子节点,而是允许 M 个子节点 (M>2),从而降低树的高度。

  2. B树优点
    B树是一种自平衡树数据结构,它维护有序数据并允许以对数时间进行搜索,顺序访问,插入和删除。B树的出现是为了弥合不同的存储级别之间的访问速度上的巨大差异,实现高效的 I/O。

  3. B树缺点
    (1) 但是 B 树的每个节点都包含数据(索引+记录),而用户的记录数据的大小很有可能远远超过了索引数据,这就需要花费更多的磁盘 I/O 操作次数来读到「有用的索引数据」。
    (2) 在我们查询位于底层的某个节点(比如 A 记录)过程中,「非 A 记录节点」里的记录数据会从磁盘加载到内存,但是这些记录数据是没用的,我们只是想读取这些节点的索引数据来做比较查询,而「非 A 记录节点」里的记录数据对我们是没用的,这样不仅增多磁盘 I/O 操作次数,也占用内存资源。
    (3) 如果使用 B 树来做范围查询的话,需要使用中序遍历,这会涉及多个节点的磁盘 I/O 问题,从而导致整体速度下降。

  4. B 树的每一个节点最多可以包括 M 个子节点,M 称为 B 树的阶,所以 B 树就是一个多叉树。

4.2 B+树

  1. B+ 树就是对 B 树做了一个升级,MySQL 中索引的数据结构就是采用了 B+ 树,B+ 树结构如下图
    image

  2. B+树的特点
    (1) 只有叶子节点(最底层的节点)才存放了数据,非叶子节点(其他上层节)仅用来存放目录项作为索引。
    (2) 非叶子节点分为不同层次,通过分层来降低每一层的搜索量;
    (3) 所有节点按照索引键大小排序,构成一个双向链表,便于范围查询;

4.3 B树与B+树的比较

  1. B+树与B树差异的点,主要是以下这几点:
    • 叶子节点(最底部的节点)才会存放实际数据(索引+记录),非叶子节点只会存放索引;
    • 所有索引都会在叶子节点出现,叶子节点之间构成一个有序链表;
    • 非叶子节点的索引也会同时存在在子节点中,并且是在子节点中所有索引的最大(或最小)。
    • 非叶子节点中有多少个子节点,就有多少个索引;
      image

5. 散列(Hash)表

5.1 散列表的基本概念

  1. 散列函数(也称哈希函数): 一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key) = Addr(这里的地址可以是数组下标,索引或者内存地址)

  2. 散列函数可能会把两个或两个以上的不同关键字映射到同一地址,这种情况称为冲突,这些发生冲突的不同关键字称为同义词

  3. 散列表(哈希表): 根据关键字而直接进行访问的数据结构.散列表建立了关键字和存储地址之间的一种直接映射关系

  4. 散列表的查找效率取决于三个因素:散列函数,处理冲突的方法和装填因子
    装填因子.散列表的装填因子一般记为α,定义为一个表的装满程度,即
    α = 表中记录数/散列表长度
    特点:α越小,填入表中的元素较少,产生冲突的可能性就越小.

5.2 散列函数的构造方法

直接定址法,除留余数法,数字分析法,平方取中法

5.3 处理冲突的方法

5.3.1 开放地址法

  1. 开放地址法:是指表中可存放新表项的空闲地址, 既向它的同义词表项开放, 又向它的非同义词表项开放. 其数学递推公式为:
    Hi = (H(key) + di) % m
    H(key)为散列函数 m表示散列表表长,di为增量序列
    取定某一增量序列后,对应的处理方法就是确定的,通常有以下4种方法:
    (1)线性探测(线性探测再散列)法:冲突发生时,顺序查看表中下一个单元,直到找出一个空闲单元或查遍全表,可能导致大量元素在相邻的散列地址上聚集起来,大大降低了查找效率
    (2)平方探测法,也称二次探测法.可以避免出现堆积问题,缺点是不能探测到散列表上的所有单元,但至少能探测到一半单元
    (3)双散列法:di = i * Hash2(key), 需要使用两个散列函数,当通过一个散列函数H(key)得到的地址发生冲突时,则利用第二个散列函数Hash2(key)计算该关键字的地址增量
    (4)伪随机序列法.

5.3.2 拉链法

  1. 为了避免非同义词发生冲突,可以把所有的同义词存储在一个线性链表中,这个线性链表由其散列地址唯一标识

5.4 局部敏感哈希(LSH)

  1. LSH 将原始数据空间中的两个相邻数据点通过相同的映射或投影变换(projection)后,这两个数据点在新的数据空间中仍然相邻的概率很大,而不相邻的数据点被映射到同一个桶的概率很小。
  2. 做法: 通过 hash function 映射变换操作,将原始数据集合分成了多个子集合,而每个子集合中的数据间是相邻的且该子集合中的元素个数较小
posted @ 2025-07-29 23:43  awei040519  阅读(30)  评论(0)    收藏  举报