当前课程知识点:数据结构(上) > 第二章 向量(下) > (d3)有序向量:Fibonacci查找 > 02D3-1 构思
欢迎同学们回来
我们这一节继续讨论有序向量的查找算法
在上一节,我们引入了所谓的二分查找
Binary search这样的一个概念
并且给出了一个基本的算法的版本
这个版本的复杂度
从渐近意义而言
应该是logn量级的
但如果进一步地细微地来
考察前面的系数
大致是1.5
我们也指出,这个1.5是可以改进的
我们现在就来看看,如何通过一种新的算法
也就是fibonaccian search
所谓的fibonacci查找
来对此进行改进
上一节的末尾
我们曾经以一个长度为7的有序向量为例
具体地给出了,在成功和失败情况下
平均查找长度的估算的过程
实际上,通过那个实例的推而广之
我们如果考虑更一般的情况
不难发现,此前所介绍的版本A
确实还有很大地改进余地
这样一个判断
更多的是,来自于这样一个观察事实
也就是说,版本A这个算法
实际上从用意上讲
它是试图通过使各种情况的搜索
在迭代次数上的平衡
来尽可能地回避掉最坏的情况
具体讲,比如所有的失败情况
大部分都会失败在同样深度的
也就是最深的这个位置
所以它表面上看是平衡的
但我们说,这其中却蕴涵着
很大的不平衡
因为我们可以看到,在整个这个查找的过程中
我们在任何一个位置上
如果要决定是向左或者是向右深入的话
其实我们所花费的成本
也就是比较的次数是不等的
准确地说
按照我们的版本,向左侧只需要一次比较
而向右侧却需要两次比较
所以这样一个表面上看
是非常公平的一个平衡
实际上在内部,却蕴涵着极大的不平衡
所以因此我们确实有理由怀疑
算法的效率是否已经达到最优
反过来,我们也可以得到
改进的一个思路
具体讲就是,既然我们已经看到
目前的机制中
向左侧确实会成本更低
向右侧更高
那么为什么我们不干脆
就把这个搜索的各种情况
如果能够画成
也是一个类似的这样一个树状图的话
做成左侧是更深的
而右侧是相对更浅的
这样一个表面上看的不平衡
却因为它恰好和这种成本
互相之间能做一个合适的补偿
反过来,有可能从整体上会得到更优
也就是说,使得整体的查找平均长度
有可能反而会缩短
具体来讲,越是成本低的转向
我们就越希望更多地做
越是成本更高的
我们越是希望它能更少地来做
所以这样的话
我们就得到了新的算法的改进的思路
那么具体这个思路怎么来兑现呢?
非常有意思
需要用到fibonacci数
不失一般性,假设我们的表的长度
也就是这个有序向量的长度N
就是某个fibonacci数减1的形式
如果确实是这样的一个形式的话
那么如这个图所示
如果这个整个长度
确实是一个fibonacci数减1的话
那我们就在其中
选择这么样一个特定的切分点
这个mi
这个mi是什么呢?
正好是整个长度
如果是第k个fibonacci数的话
那么它的位置就是
第k-1个fibonacci数,再减1
换而言之
如果以这个点为切分的话
那么左边这个子向量的长度
就恰好是第k-1个fibonacci数
再减1
而右边呢,恰巧是
fibonacci数第k-2项,再减1
可见这样一种切分的好处就是
在任何时候
只要按照这样来切分
切分下来,无论是向左还是向右
它都会从长度上讲
依然保持某个fibonacci数
再减1的形式
我们稍后就会看到,这种形式
实际上还非常巧
恰好是最优的
我们先来看,它具体是怎么实现的
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-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)深度优先搜索--作业
-第六章 图--本章测验