大话数据结构 -- 第八章 查找

查找概论

查找按照操作方式分为:静态查找和动态查找

  1. 静态查找:只进行查找操作。主要操作有:
    • 查询数据元素是否在查找表中
    • 查询数据元素和各种属性
  2. 动态查找:查找过程中同时进行插入和删除操作。主要操作有:
    • 插入数据元素
    • 删除数据元素

顺序表查找

  • 顺序查找:从表中第一个数据元素开始,逐个和目标元素进行比较,直至表尾。
  • 顺序表的查找可以从表尾开始倒序查找,这样就免去了越界检查。
  • 顺序查找复杂度:o(n),n很大时,查找效率低

有序表查找(折半查找、插值查找、斐波那契查找)

  1. 折半查找
    这里写图片描述
    折半查找复杂度:o(logn)

  2. 插值查找

    • 插值查找:要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,核心在于插值公式: mod=low+keya[low]a[high]a[low]
    • 推导过程:
      (keya[low]):(midlow)=(a[high]a[low]):(highlow)
    • 插值查找的要求:查找表的数据分布比较均匀
    • 插值查找复杂度:o(logn),平均性能比折半查找要好得多
  3. 斐波那契查找
    • 斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为Fn,完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
      斐波那契查找
      这里写图片描述
    • 斐波那契查找复杂度:o(logn),平均性能优于折半查找,但是目标元素若是都处于左侧长半区,则查找效率要低于折半查找。

线性索引查找(稠密索引、分块索引、倒排索引)

线性索引表中的数据不都是有序的,索引按照结构分为线性索引、树形索引和多级索引,这里只介绍线性索引(索引表):稠密索引、分块索引、倒排索引。

  1. 稠密索引:数据集中的每个记录对应一个索引项。
    • 稠密索引的索引表,索引项一定是按照关键码有序的排列
    • 若数据集非常大,则查找性能大大下降
  2. 分块索引:数据集的记录分成了若干块,并且这些块满足两个条件:
    • 块内无序:每一块内的记录不要求有序
    • 块间有序:第n+1块所有记录的所有关键字均大于第一块所有关键字
    • 分块索引的索引项结构分为三项:最大关键码、块内记录个数、块首元素指针
    • 分块索引的查找,分为两步:
      • 查找块的位置(可使用折半、插值等算法)
      • 顺序查找块内元素
    • 分块查找的复杂度:,比顺序查找快,但和折半查找有不少差距。
  3. 倒排索引:由属性值来确定记录的位置,而不是由记录来确定属性值。
    • 索引表具有通用项:次关键字和记录号表,记录号表存储具有相同次关键字的所有记录的记录号,这样的索引方法就是倒排索引。
    • 倒排索引的优点:查找记录非常快,不用读取记录就可以得到结果。
    • 倒排索引的缺点:记录号不定长,若记录号较多,则维护较困难。

二叉排序树

  1. 二叉排序树,又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树:
    • 若它的左子树不空,则左子树上所有结点的值均小于它的根结构的值;
    • 若它的右子树不空,则右子树上所有结点的值均大于它的根节点的值;
    • 它的左、右子树也分别为二叉排序树。
  2. 二叉排序树的查找
    这里写图片描述
    这里写图片描述
  3. 二叉排序树的插入
    这里写图片描述
  4. 二叉排序树的删除
    这里写图片描述

平衡二叉树

  1. 平衡二叉树:一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1。
    • 平衡因子BF:二叉树上结点的左子树深度减去右子树深度的值
    • 平衡因子只可能是-1,0,1
  2. 最小不平衡子树:距离插入点最近的,且平衡因子的绝对值大于1的结点为根的子树。
  3. 平衡二叉树的实现算法:这一块的内容网上有博客整理得很好,在这里直接引用过来,并在最后部分加上自己的理解。
    详见另一博客:平衡二叉树实现

散列表(哈希表)查找概述

  • 散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。
  • 对应关系f称为散列函数,又称为哈希函数.
  • 采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间为散列表或哈希表
  • 冲突:两个关键字key1≠key2,但是却有f(key1) = f(key2),这种现象叫做冲突,并把key1和key2称为散列函数的同义词。

散列函数的构造方法

  1. 好的散列函数:计算简单 、 散列地址分布均匀
  2. 构造方法:
    • 直接定址法: f(key)=a×key+b
      • 优点: 简单、均匀,不会产生冲突
      • 缺点:需事先知道关键字分布情况,适合查找表较小且连续情况,并不常用
    • 数字分析法:用到的一个方法是抽取,即使用关键字的一部分来计算散列存储位置
      • 适合处理关键字位数比较大的情况
    • 平方取中法:适合于不知道关键字的分布,而位数又不是很大的情况
    • 折叠法:适合事先不知道关键字分布,关键字位数较多的情况
    • 除留余数法: f(key)=keymodp(pm)
      • 本方法的关键在于选择合适的p
    • 随机数法: f(key)=random(key)

处理散列冲突的方法

  1. 开放定址法:开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。
    • 线性探测法: fi(key)=(f(key)+di)modm(di=1,2,3,...,m1)
    • 二次探测法:
      fi(key)=(f(key)+di)modm(di=12,12,22,22...)
    • 随机探测法:
      fi(key)=(f(key)+di)modm(di)
  2. 再散列函数法:一个散列函数产生冲突的时候,换另一个散列函数
  3. 链地址法:在记录表中的每个位置都建立一个单链表,若有冲突,则给单链表增加结点。
  4. 公共溢出区法:单独另创建一个表,来存储冲突的记录。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值