当前位置: 首页 > news >正文

数据结构——四十、折半查找(王道408)

文章目录

  • 前言
  • 一.算法思想
    • 1.思路
    • 2.举例
      • 1.查找成功
      • 2.查找失败
  • 二.代码实现
  • 三.查找效率分析
    • 1.分析过程
    • 2.结论
  • 四.折半查找判定树的特性
    • 1.右子树结点数-左子树结点数=0或1
      • 1.分析过程
      • 2.结论
      • 3.题目
    • 2.折半查找的判定树一定是平衡二叉树
    • 3.折半查找的判定树一定是二叉排序树
  • 五.折半查找的查找效率
  • 六.知识回顾与重要考点
  • 结语

前言

本文介绍了折半查找(二分查找)的基本思想、实现方法和查找效率分析。折半查找仅适用于有序顺序表,通过不断缩小查找区间来定位目标元素。文章通过示例演示了查找成功和失败的流程,并提供了升序和降序排列时的C语言实现代码。在效率分析部分,通过构建判定树计算了成功和失败情况下的平均查找长度(ASL),指出折半查找判定树具有右子树结点数-左子树结点数=0或1的特性,且一定是平衡二叉树和二叉排序树。最后说明元素个数为n时,判定树高度为⌈log₂(n+1)⌉(不含失败结点)或⌈log₂(n+1)⌉+1(含失败结点)。

一.算法思想

1.思路

  • 折半查找,又称“二分查找”,仅适用于有序顺序表
  • 当前检查的这个元素,把目前有可能出现目标元素的这一整个区间一分为二,分为了左边的区间和右边的区间,根据我们想要找的这个关键字和当前被检查元素的这个大小关系,我们就可以知道我们到底应该是在左边还是右边来查找
  • 循环上述操作,在不停的缩小区间后,如果元素存在

2.举例

1.查找成功

在这里插入图片描述

  • 假设我们现在要在这个有序的顺序表当中找到33这个元素,那首先我们会用两个指针,low和high来分别指向我们目前要搜索的这个区间范围
    在这里插入图片描述
  • 第一轮我们要检查的元素是low和high他们中间的一个元素,我们用一个指针mid=(low+high)/2来指向它
    在这里插入图片描述
  • 因此第一个检查的元素是29,子现在对比mid的所指向的元素,还有我们的目标关键字33会发现我们要查找的目标要大于当前mid的所指向的这个元素,所以如果33这个元素存在的话,那么一定是在mid的所指位置的右边这个部分,因此我们要做的就是把low这个指针指向6这个位置
    在这里插入图片描述
  • 同样是检查 low和high这个区域内的中间那个元素mid,这个元素的值是37,37是要大于33的,所以如果33存在的话,那么肯定是在mid的所指位置的左边这个区域
    在这里插入图片描述
  • 因此接下来我们会让high指针指向7这个位置
    在这里插入图片描述
  • 接下来操作也是一样,mid指针指向6,32<33,因此在mid的右边寻找,因此接下来我们会让low这个指针指向mid的右边那个位置
    在这里插入图片描述
  • 同样的,此时mid指向7,33=33,恰好就是我们要查找的目标

2.查找失败

在这里插入图片描述

  1. 其他步骤和之前一样,只是最后一步的判断条件略有不同
    在这里插入图片描述
  2. 此时检查的就是10这个元素,那由于我们要找的目标12依然是大于10的,所以如果12存在的话,那只有可能是在mid的所指的右边那个区间内,所以和刚才的处理逻辑一样,我们会让lowi这个值等于mid+1
    在这里插入图片描述
  • 可以看到low>high,因此查找失败

二.代码实现

typedef struct{//查找表的数据结构(顺序表)Element *elem;//动态数组基址int TableLen;//表的长度
}SSTable;
//折半查找(元素升序排列)
int Binary_Search(SSTable L, ElemType key){int low=0, high=L. TableLen-1, mid;while(low<=high){mid=(low+high)/2; //取中间位置if(L. elem[mid]==key)return mid; //查找成功则返回所在位置else if(L. elem[mid]>key)high=mid-1; //从前半部分继续查找elselow=mid+1; //从后半部分继续查找}return -1; //查找失败,返回-1
}
//折半查找(元素降序排列)
int Binary_Search(SSTable L, ElemType key){int low=0, high=L. TableLen-1, mid;while(low<=high){mid=(low+high)/2; //取中间位置if(L. elem[mid]==key)return mid; //查找成功则返回所在位置else if(L. elem[mid]<key)high=mid-1; //从前半部分继续查找elselow=mid+1; //从后半部分继续查找}return -1; //查找失败,返回-1
}

三.查找效率分析

1.分析过程

在这里插入图片描述

  • 如果我们要查找的关键字刚好是29的话,只需要经过一次关键字对比
    在这里插入图片描述

  • 我们要查找的关键字小于(大于)29的话,通过第二次的关键字对比,我们可以找到的元素应该是13(37)
    在这里插入图片描述

  • 那如果依然不是这两个元素,那接下来也是一样的
    在这里插入图片描述

  • 此时我们有可能会检查的元素有7,16,32,41
    在这里插入图片描述

  • 如果查了这几个元素还没有找到目标的话,接下来进行之前一样的操作
    在这里插入图片描述

  • 所以对于刚开始给出的这个查找表,在查找成功的情况下,我们最多有可能进行4轮查找,这是查找成功的情况

  • 而对于查找失败的情况,再补上失败节点就可以
    在这里插入图片描述

  • 也就是说我们要查找的关键字如果落在这紫色方框内的某一个区间内,那么最终我们肯定是查找失败的

2.结论

  • A S L 成功 = ( 1 ∗ 1 + 2 ∗ 2 + 3 ∗ 4 + 4 ∗ 4 ) / 11 = 3 ASL_\text{成功} = (1*1+2*2+3*4+4*4)/11 = 3 ASL成功=(11+22+34+44)/11=3
  • A S L 失败 = ( 3 ∗ 4 + 4 ∗ 8 ) / 12 = 11 / 3 ASL_\text{失败}=(3*4+4*8)/12=11/3 ASL失败=(34+48)/12=11/3

四.折半查找判定树的特性

1.右子树结点数-左子树结点数=0或1

1.分析过程

  • 如果当前low和high之间有奇数个元素,则mid分隔后左右两部分元素个数相等
    在这里插入图片描述

  • 如果当前low和high之间有偶数个元素,则mid分隔后左半部分比右半部分少一个元素
    在这里插入图片描述

2.结论

  • 折半查找的判定树中,若 m i d = ⌊ ( l o w + + h i g h ) / 2 ⌋ mid=\lfloor(low++high)/2\rfloor mid=⌊(low++high)/2,则对于任何一个结点,必有:
    右子树结点数-左子树结点数=0或1

3.题目

  • 练习:若 m i d = ⌊ ( l o w + + h i g h ) / 2 ⌋ mid=\lfloor(low++high)/2\rfloor mid=⌊(low++high)/2,画出含1个元素、2个元素、3个元素…16个元素的查找表对应的折半查找判定树,注:暂不考虑失败结点(Key:右子树结点数-左子树结点数=0或1
    解:1.一个元素:
    在这里插入图片描述
    2.两个元素,由于右子树结点只可能比左子树更多,因此:在这里插入图片描述
    3.三个元素,由于右子树最多比左子树多一个结点,因此:在这里插入图片描述
    4.十六个元素,按照之前的规律依次往后推演
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

注:图中数字只是一个编号,并不是关键字的值

一点小规律:从根节点出发,编号的顺序是左孩子的左孩子编号->最左边的堂兄弟结点的左孩子的左孩子编号->兄弟结点的左孩子的左孩子编号->最左边的堂兄弟结点最近的兄弟结点的左孩子的左孩子编号->…(以此类推)
左孩子编完后编右孩子,右孩子的编号顺序也是和左孩子一样的

2.折半查找的判定树一定是平衡二叉树

  • 任何一个节点的左子树和右子树的深度之差都不会超过1
  • 折半查找的判定树中,只有最下面一层是不满的因此,元素个数为n时树高 h = ⌈ log ⁡ 2 ( n + 1 ) ⌉ h=\left\lceil\log_2(n+1)\right\rceil h=log2(n+1)(和完全二叉树相同)(不包含失败结点,如果包含失败结点,则其树高 h = ⌈ log ⁡ 2 ( n + 1 ) ⌉ + 1 h=\left\lceil\log_2(n+1)\right\rceil+1 h=log2(n+1)+1)

3.折半查找的判定树一定是二叉排序树

  • 判定树结点关键字:左<中<右,满足二叉排序树的定义
  • 失败结点:n+1个(等于成功结点的空链域数量)

五.折半查找的查找效率

  • 查找成功的ASL≤h(树的高度)
  • 查找失败的ASL≤h(树的高度)
  • 折半查找的时间复杂度 = O ( log ⁡ 2 n ) O(\log_{2}n) O(log2n)

六.知识回顾与重要考点

在这里插入图片描述

  • 拓展思考
    折半查找时间复杂度=O(log₂n)
    顺序查找的时间复杂度=O(n)
    那么,折半查找的速度一定比顺序查找更快?
    答:不一定,只是平均查找速度更快
    在这里插入图片描述
    如果 m i d = ⌈ ( l o w + h i g h ) / 2 ⌉ mid=\lceil(low+high)/2\rceil mid=⌈(low+high)/2
    那么,判定树是什么样子?
    答:
    在这里插入图片描述
    如果当前low和high之间有奇数个元素,则mid分隔后,左右两部分元素个数相等
    在这里插入图片描述
    如果当前low和high之间有偶数个元素,则mid分隔后,左半部分比右半部分多一个元素
    在这里插入图片描述

结语

二更,最近事情比较多,更新会有延迟😖

如果想查看更多章节,请点击:一、数据结构专栏导航页

http://www.dtcms.com/a/589615.html

相关文章:

  • 操作系统 内存(5)虚拟内存机制
  • 郑州网站建设专业乐云seowordpress user role
  • JavaScript 的 Web APIs 入门到实战全总结(day7):从数据处理到交互落地的全链路实战(附实战案例代码)
  • 分类型网站建设付费推广外包
  • 17_FastMCP 2.x 中文文档之FastMCP服务端高级功能:LLM采样详解
  • 集团网站建设制作费用百度公司是国企还是私企
  • Go Channel 深度指南:规范、避坑与开源实践
  • Postman 脚本控制特定请求的执行流程(跳过执行)
  • Kubernetes Deployment 控制器
  • 网络体系结构-物理层
  • 色彩搭配 网站无障碍网站建设方案
  • 网站建设制作公一般做个网站多少做网站多少钱
  • 商业网站建站目的官网建站系统
  • HCCDE-GaussDB相关计算题
  • 从SOMEIP看SOA,汽车电子电器架构的转变
  • 免费自己制作logo的网站wordpress百度百科
  • asp制作网站教程猎头公司网站素材
  • Java--JVM
  • 英语学习——单词篇(第十七天)
  • 福州做网站wordpress修改footer
  • 顺序表vector--------练习题9题解
  • 深入浅出:低噪声放大器(LNA)与USB芯片——无线与有线通信的基石
  • C++线程操作
  • 培训网站网站建设上海 网站建设google
  • OpenCV 第10课 图像处理—阈值处理
  • 力扣刷题-借助哈希完成一次遍历
  • 网络图标误报?电脑显示无网却能上网的快速修复法
  • 二七区做网站动画设计培训机构
  • 做网站九州科技哈尔滨网络公司定制开发
  • 链动2+1模式、AI智能名片与S2B2C商城小程序:破解直播电商流量转化困局的创新路径