这个数列在编写程序的过程中,应该被无数次提起,今天再次提起,作为动态规划的一个引入。
动态规划被人总结为:

递推 + Cache

而使用Cache方式的Fib数列计算也是很酷的。代码非常简洁,但是如果没有这种思想,就很难理解为什么这么写了。
另一种情况是,我们知道要用个数组去缓存,但是在具体实现的过程中,就很难翻译成代码,这里姑且当作一种反思吧。

OK,先看代码:

#define MAXN 45
#define UNKNOWN -1
#include<stdio.h>long f[MAXN+1]; //用于缓存已经计算的数组
long fib_c(int n)
{if(f[n] == UNKNOWN){f[n] = fib_c(n-1) + fib_c(n-2);}return f[n];
}
long fib_c_driver(int n)
{//初始化缓存数组f[0] = 0;f[1] = 1;for(int i = 2; i <= n; i++){f[i] = UNKNOWN;}return(fib_c(n)); //计算
}
int main(void)
{printf("%d\n",fib_c_driver(3));
}

首先如果计算一个斐波那契数,我们调用fib_c_driver函数。这个函数将会把缓存数组初始化,前两个数是我们已知的0,1,第三个开始到以后都看作未知,初始化为-1,这个数字随便写,但是不要是一个可能的斐波那契数。
然后将调用fib_c函数去递归计算,这个过程稍微解释一下:
进来以后,先判断数组中是否已经缓存,如果没有缓存,就递归计算。

如果求的是fib_c(0), fib_c(1),直接返回已经有的数值。

如果求得是fib_c(2),一看,数组中没有缓存,于是计算f[2] = f[1] + f[0],但是这么写就不对,因为f[1],f[0]也是需要计算得来。因为0,1开始就知道,如果计算的是f[45], 直接返回了f[44] + f[43],那么得到的是-2,根本不是我们想要的数,所以,f[2] 后面写的是fib_c(1) + fib_c(0)。

广义一些即为:f[n] = fib_c(n-1) + fib_c(n-2);

那么这个与平常写的那个递归有何区别呢?
我们看f[4] = fib_c(3) + fib_c(2),转换成去求fib_c(3)和fib_c(2)。
fib_c(3)进来是判断f[3] == UNKNOWN,结果是f[3]已经缓存好了,不用再去计算。同样f[2]也是这样。

这里用树形图展开,如果未加缓存的计算,将是这棵树的深度优先遍历,每一个树枝都将被走一遍。而如果是缓存,则只需要走最左边的那个路径:F(6 ) –> F(5)–>F(4)–>F(3)–>F(2)–>F(1),F(0),然后整个数组就被写好了。这下减掉多少树枝!

当然,你能感受到,既然是简单的缓存数据,干嘛还要用递归的方式去缓存呢?直接来不就好~
以下:

//非递归调用版本
long fib_dp(int n)
{f[0] = 0;f[1] = 1;for(int i = 2; i <= n; i++){f[i] = f[i-1] + f[i-2];}return f[n];
}

这个简洁到不用解释了。比上面递归的版本要优秀一些。但是上面的递归大概也可以看作走到这里的缓存吧!

到这里似乎可以结束了,但是我们看到,当我们计算时,需要开辟一个数组,存储了从0,1,1,2,3,5….所有的数据,这…是不是有点奢侈?

对的,虽然时间宝贵,空间也相当宝贵。
我们计算时,当前的状态仅仅与回退到之前的两个状态相关,那么是否可以只用一个变量解决这种问题呢?
答案是可以的。

long fib_ultimate(int n)
{long back1 = 1, back2 = 0;long next;if(n == 0){return 0;}for(int i = 2; i < n; i++){next = back1 + back2;back2 = back1;//先求得back2,再求得back1back1 = next;}return back1 + back2;
}

这就有了一些动态规划中,状态转移方程的意思了!

但是值得注意的是,优化了空间后,取得单个斐波那契数值加快了,但是并不存储过去的值。即,计算Fib(45),就是单纯的计算出这个值,这个过程中产生的其他值都被抛弃了。再需要Fib(45),或者Fib(30)等,需要重新计算。如果基于数组的缓存,计算Fib(45)后,从Fib(0)到Fib(45)的值,随用随取,可以做到在O(1)内得到结果。所以,具体问题具体分析。时间优化是必要之举,空间优化适当选择。

基于Cache的Fibonacci数列的计算相关推荐

  1. C++项目參考解答:求Fibonacci数列

    [项目:求Fibonacci数列] Fibonacci数列在计算科学.经济学等领域中广泛使用,其特点是:第一.二个数是1,从第3个数開始,每一个数是其前两个数之和.据此,这个数列为:1 1 2 3 5 ...

  2. 试题1 入门训练 Fibonacci数列

    问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n ...

  3. python汉诺塔用循环结构实现_Python基于递归算法实现的汉诺塔与Fibonacci数列

    这篇文章主要介绍了Python基于递归算法实现的汉诺塔与Fibonacci数列,结合实例形式分析了汉诺塔与Fibonacci数列的递归实现技巧,需要的朋友可以参考下 本文实例讲述了Python基于递归 ...

  4. fibonacci数列python_从 Python 计算 Fibonacci 数列说起

    从 Python 计算 Fibonacci 数列说起 09 Oct, 2012 编程语言之争,争到最后大都就是在争论速度了,速度当然很重要,毕竟现实的物理设备和人类的想象力之间差距还是蛮大的,然而比较 ...

  5. 计算Fibonacci数列第n项的第8种方法(数学推导与Python实现)

    感谢山东工商学院学院厉玉蓉老师提供的完美数学推导,我在重写和整理时略加修改,比如变量替换时她喜欢用字母z,而我喜欢用x,哈哈.当然,还有另外几个小地方^_^ 本文从Fibonacci数列第n项的通项公 ...

  6. 6-3 计算Fibonacci数列每一项时所需的递归调用次数 (10 分)

    计算并打印Fibonacci数列每一项时所需的递归调用次数,数列第一项从1开始. 要求: 1)定义表示调用次数的全局变量count: 2)定义用递归方法求Fibonacci数列的Fib()函数. 函数 ...

  7. 7-2 计算Fibonacci数列的前N(N<=20)项 (10 分)

    7-2 计算Fibonacci数列的前N(N<=20)项 (10 分) 编译器:C++ (g++) 从键盘读入正整数N(N<=20),用动态分配空间的方法计算Fibonacci数列的前N项 ...

  8. 算法 · 深入理解 Fibonacci 数列计算及黄金分割

    在自然界中,有一串数字我们时常能看到,它的前几项序列是: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233- 如果用数学语言描述,它的递归形式是这样的 ...

  9. C语言计算Fibonacci数列并将Fibonacci数列并写入文件中

    计算Fibonacci数列并将Fibonacci数列 写入文件中 #include<stdio.h> #define N 20 int main() {int f[N]={0,1};int ...

最新文章

  1. keil中文乱码解决和个人习惯字体设置
  2. Java常量池解析与字符串intern简介
  3. keras 自定义评估函数和损失函数loss训练模型后加载模型出现ValueError: Unknown metric function:fbeta_score
  4. Codeforces Round #654 (Div. 2)
  5. STC用PCA测量脉宽_教你测量玉手镯圈号及如何轻松快速摘戴玉手镯?
  6. C++使用openssl实现aes加解密,其中加密是string到文件,解密是文件到string,切合项目背景
  7. 牛客 Bang! Bang!(动态规划)
  8. 【java】java 的网络地址类 InetSocketAddress
  9. 虚拟机危险!一个存在11年的缓冲区溢出漏洞--毒液
  10. 关于silverlight主题皮肤(一)
  11. Übersicht for mac(自定义桌面工具)v1.6(68)最新版
  12. Linux电源管理(2)_Generic PM之基本概念和软件架构
  13. K8S 1.23 metrics-server及cadvisor 杂记
  14. 2018最新圣思园JavaSE实地培训系列视频教程
  15. 我的同事们(四): Sang Shin
  16. 好玩又赚钱的链游有哪些?
  17. Python通过m3u8文件下载合并ts视频
  18. 亚利桑那州立大学计算机专业,美国大学亚利桑那州立大学计算机科学专业课程设置...
  19. 2020年中国空气压缩机行业发展现状、竞争格局及未来发展趋势分析,国内市场竞争激烈,市场规模将破600亿元「图」
  20. 个人家用nas_个人与家庭NAS怎么样,您知道吗?

热门文章

  1. php 输出tab_php实现读取和写入tab分割的文件
  2. 分页offset格式_MySQL中limit分页查询性能问题分析
  3. ansys icem cfd网格划分技术实例详解_详解航空燃油滑油3D打印热交换器设计流程...
  4. nbu备份oracle rac,利用NETBACKUP将备份写到磁盘上
  5. java虚拟机手机系统,微软java虚拟机
  6. 想不想修真鸿蒙接引码,想不想修真接引码介绍_想不想修真接引码是什么_玩游戏网...
  7. php怎么防止爬虫,PHP语言学习之php 防止爬虫设置
  8. 5双机配置_CentOS 7 高可用双机热备实现
  9. sql重命名数据库_SQL重命名数据库
  10. Spring ActiveMQ示例(第2部分)