当前课程知识点:数据结构(上) > 第二章 向量(上) > (d2)有序向量:二分查找 > 02D2-7 查找长度
有序向量的查找是非常基本的一种算法
而且它存在多个版本
因此除了我们上面利用渐近的复杂度
能够从总体上把握它的大体性能以外
我们还需要对不同版本算法的性能
做更加细微的评定
具体来说 也就是来考察
渐近复杂度logn前面的那个常系数
而具体地 在统计和分析的时候
我们更多的是来考量
所谓的关键码的比较操作次数
也就是在其中所执行的if语句的次数
我们将此称作是
不同的算法在不同的情况下
所对应的查找长度
那么我们也需要从不同的情况出发
比如说最典型的是成功和失败两种情况
并且从不同的侧面
最好、最坏以及平均 不同的这样(注:种)侧面
来进行评估
比如 针对我们这里所说的
二分查找的版本A而言
我们在教材以及习题解析中
都给出了这么样一个分析
最后的结论是说
无论是失败还是成功的情况
平均的查找长度大体都是
以1.5为系数的一个logn
以下呢
我们不妨来看一个具体的实例
这是一个由七个元素构成的有序向量
其实它的数值是具体是多少 我们并不在意
只要它是非降排列的就可以
如果我们把整个的算法改写成递归的形式
那么整个的那个不同情况的递归跟踪
将构成这么样一个递归跟踪图
我们来看一下 这里总共有
七种成功的情况
更准确地讲 对于其中的每一个元素
都各自有一种成功的情况
假设它们出现的概率均等
那么相应地呢
我们还会有7+1
也就是8种失败的情况
这也是一个普遍的规律
我们先来看成功的情况
按照刚才的算法
如果是成功在中间这个元素
也就是这个元素
它需要经过几次比较呢?
我们说是两次
第一次 它试图向左 结果失败
第二次 它试图向右也失败
最后告诉它说
目标既不小于也不大于当前这个元素
所以它就在这命中
但是为此我们需要花费两次比较
好 我们再来看这个元素
这个元素 如果是它要成功的话
我们说肯定是首先
经过了一次比较 判断比第一个切分点要小
所以才会深入到左侧这个向量中来
并且进而跟这个相比
同样在这个地方
我们也要经过一次向左和一次试图向右
最后确定在这块命中
在这个结点上 我们花费了两次
而转向这个子向量 我们花费了一次
所以累计而言 在这里我们应该花费的是三次
好 同样在这边 也是这种情况
本身这个地方要花费两次
而这个地方转向 大家注意这是不对称的
往这个左方向转向 我们只需要一次比对
但是向右侧转向 我们却需要花费两次
所以本身转过来两次
在这个本地又花费两次
所以累计在这个节点 如果是成功查找到的话
需要的成本是四次比较
好 接下来 我们再来看这个方向继续
如果是成功在这个位置的话
那么它是经过了
在这个位置一次比较 转入到这个子向量
然后再在这个位置经过一次比较
才转入这个子向量
并且针对这个切分点来做比较
同样 如果在这块命中的话
在这个本地要再进行两次
所以一次 再加一次 再加两次
我们需要四次
同样地 大家可以按照这种方法验证
这个地方是五次
如果成功在这个地方 也需要五次
而成功在这个地方呢
是最耗时的 需要六次
所以累计起来 我们做一个心算
我们可以看到
两次 加三次 再加四次 这是九次
再加上底下是二十
所以总共是二十九次
而总共呢 有七种情况
我们说大致等于多少呢?
大致等于4再略加一些
我们再来看失败的情况
也就是这八种情况
那么对于最左侧的这个情况
如果在这边失败的话
那么我们需要在这个位置做一次比较
从而转入这个位置 然后再做一次比较
最终判定失败
所以在这个位置对应的次数就是三次
而这个位置呢 如果失败的话呢
此前的一次、两次情况完全一样
不同的是在于 最后这一个位置
我们这个时候为了拐向右侧
实际上需要进行的是两次
而不是像刚才那样的一次比较
所以相应的总体的
比较的次数 要多加一次 是四次
同样的这边 我们也可以看到
写的也是四次 为什么呢?
我们来走一遍
从这个方向深入到左侧 这是一次比较
但是每次凡是向右都是两次
凡是向左都是一次
所以一次 加两次 再加上一次 得到四次
相应的这边 也会多一次 是五次
而这边呢 我们说也是四次 为什么呢?
因为这条路径上向右 这是两次
向左是一次
再向左一次 所以累计是四次
而这个失败的情况呢
是有一次向右 累计两次
再一次向左 累计一次
然后再向右 两次
所以是二加一 加二 等于五次
同样地 这边也是六次
把这些我们总和加在一起
我们也可以去心算一下
总共八种情况
累计需要比较的次数是36次
如果这些情况是等概率出现的话
比较的次数正好平均是4.5
4.5大概等于多少呢?
无论是上面还是下面 大概都等于
log以2为底 这个长度是7
或者是说 随着这个向量的更大
我们更喜欢用它再加1来粗略地估算
也就是8
所以这个系数大致就是
我们刚才所说的1.5
那么这个1.5是不是已经最好了呢?
我们说其实还有改进的余地
这也是我们接下来的两节
需要讨论的问题
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验