当前课程知识点:数据结构(上) > 第一章 绪论(下) > (xc)动态规划 > 01XC-5: Fib():迭代
去掉这样的重复以后
我们的第一种改进方法
是直截了当的 也就是说
在我们每一次试图生成
一个新的递归实例的时候
都去检查一下
它 当然也可能是它
或者是它 无论是谁
是否在此前 已经被唤醒
并且计算 得出过相应的结果
如果是 那么我们就
不必再重新的唤醒它
并执行一次计算
当然 也会包括引发后续的计算
而是直接把原先的结果
取出来就可以了
没错 这是最好的方法之一
我们把这种方法称作
记忆法 memoization
大家记住 这里并没有写错
不是memorization
而是memoization
具体来说 对于这个例子而言
我们可以将Fibonacci数的各项
所计算的结果制成一个表格
初始化的时候 这个表里
可能 比如说 都是负数
以表示还没有计算出来
而一旦某一个递归实例
比如说 第二项Fibonacci数
已经被调用
并且执行计算出结果
我们就将相应的结果
存入表中对应的那一项
无论是0 1 2 3
还是诸如此类地
以后呢 一旦每一次
需要去再次唤醒
这个递归实例的时候
我们按照刚才的设计
都会首先去查这个表
并且会发现表中的项
已经不再是一个负数
这就意味着这项
是此前已经计算出来的
所以它会智能的
回避掉这次调用
包括后续引起的那些调用
从而在O(1)的时间内
返回所需要的结果
这种方法非常好
当然 对这种方法而言
对原来的程序的改进 也不是很大
虽然这里我们没有给出具体的形式
但是大致可以想像的到
也就是在程序的入口处
增加这么一句
对于全局表格的查询
只有在表格中还没有有效的
这样的一个结果的时候
才会执行实质的计算
这样的话 我们就有效地
克服了刚才的缺点
第二种方法
更加通用而且更加自然
我们可以认为
就这个例子而言
如果说此前
递归的计算方向是从大到小
自顶而下的话
我们受到刚才
上楼梯那个问题的启发
不妨倒过来
改为自小而大 自底而上
这样由原来的递归算法
改进为迭代的一个算法
我们说同样可以完成刚才的工作
而且更重要的是
它在每一个台阶上
只需要停留一次
总体而言
可以使得复杂度更低
这样一个算法
我们具体的可以落实为
这样一张图
也就是说
不妨用两个变量f和g
分别来记忆当前
我所处的相邻的两级台阶
最开始当然是0和1
接下来就是1和2
再2和3 继续3和4 4和5
就这个例子而言
一直到最终的6
很好
这确实是一个可行的方法
而且它的代码也非常的简明
我们可以看一下
初始化 然后不断地迭代
每一次迭代都通过
这样的两句赋值语句
更新这两个变量f和g
使它始终指向
这个楼梯中相邻的两阶
也可以说是在Fibonacci数列中
当前相邻的两项
它们整体地呈现一种
交替的滚动的方式
不断地向前推进
直到我们所希望得到的最终的解
这个算法需要多少时间呢?
我们可以看到
除了这样的一个循环
没有任何更多的
引起复杂度的部分
它的复杂度 简明地可以看出
是由n来控制的
与n是呈线性的关系
也就是说 它只需要O(n)的时间
而且更重要的是
我们在这里
只需要f和g两个存储单元
总体而言
只需要常数的空间
如果大家回去估算的话 会发现
我们刚才的那个递归的版本
在空间上也同样是非常破费的
具体来讲 它需要O(n)的空间
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-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)深度优先搜索--作业
-第六章 图--本章测验