斐波那契数与二分法的递归与非递归算法及其复杂度分析
1. 什么是斐波那契数?
这里我借用百度百科上的解释:斐波那契数,亦称之为斐波那契数列(意大利语: Successione di Fibonacci),又称黄金分割数列、费波那西数列、费波拿契数、费氏数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*),用文字来说,就是斐波那契数列列由 0 和 1 开始,之后的斐波那契数列系数就由之前的两数相加。特别指出:0不是第一项,而是第零项。
2. 求第N个斐波那契数
求第N个斐波那契数比较简单可以直接套用公式n = 0,1 时,fib(n) = 1;n > =2 时,fib(n) = fib(n-2) + fib(n-1)在计算时有两种算法:递归和非递归。如下:
1 //非递归算法 2 long long fib1(size_t N) { 3 long long a = 0, b = 1, c = 0; 4 if (N < 2) { 5 return N; 6 } 7 else { 8 for (long long i = 2; i <= N; ++i) { 9 c = a + b; 10 a = b; 11 b = c; 12 } 13 } 14 return c; 15 } 16 int main() 17 { 18 printf("%lld", fib1(10)); 19 getchar(); 20 return 0; 21 } //此算法最大的优点是不存在重复计算,故效率比递归算法快的多得多。
1 //递归算法 2 long long fib2(size_t N) { 3 if (N < 2) 4 return N; 5 return fib2(N - 1) + fib2(N - 2); 6 } 7 int main() 8 { 9 printf("%lld", fib2(10)); 10 getchar(); 11 return 0; 12 }
递归可以使程序看起来比较简洁,但缺点是效率比较低,并且可能导致栈溢出,当需要计算的数稍大一点,就需要很长的计算时间,因此需要灵活使用递归。
3. 二分法查找
3.1 二分查找的非递归算法
1 template<typename T> 2 T* BinarySearch(T* array,int number,const T& data) //data要查找的数,number查找范围长度,array要查找的数组 3 { 4 assert(number>=0); 5 int left = 0; 6 int right = number-1; 7 while (right >= left) 8 { 9 int mid = (left&right) + ((left^right)>>1); 10 if (array[mid] > data) 11 { 12 right = mid - 1; 13 } 14 else if (array[mid] < data) 15 { 16 left = mid + 1; 17 } 18 else 19 { 20 return (array + mid); 21 } 22 } 23 return NULL; 24 }
3.2 二分查找递归算法
1 template<typename T> 2 T* BinarySearch(T* left,T* right,const T& data) 3 { 4 assert(left); 5 assert(right); 6 if (right >=left) 7 { 8 T* mid =left+(right-left)/2; 9 if (*mid == data) 10 return mid; 11 else 12 return *mid > data ? BinarySearch(left, mid - 1, data) : BinarySearch(mid + 1, right, data); 13 } 14 else 15 { 16 return NULL; 17 } 18 }
4. 时间复杂度与空间复杂度
5. 斐波那契数的时间复杂度与空间复杂度分析
5.1 非递归算法时间复杂度分析
使用非递归算法求到第n个斐波那契数,是从第2个数开始,将前两个数相加求求后一个数,再将后一个数赋值给前一个数,再计算前两个数相加的结果。依次类推直到第n个数,用n-1个数和n-2个数相加求出结果,这样的好处是,我们只计算了n-1次就求出了结果,即时间复杂度为O(n);我们以代码中测试数10为例详解求第十个数的过程。当N=10时,进入函数首先判断,然后走下面的分支开始计算
计算了N-1次,得出了结果所以时间复杂度是O(N)。
非递归算法空间复杂度分析此函数内部最多时一共开辟了a, b, c, i四个变量空间复杂度是常数,即为O(1)。
5.2 递归算法时间复杂度分析
在递归算法中,求解fib2(n),把它推到求解fib2(n-1)和fib2(n-2)。也就是说,为计算fib2(n),必须先计算
fib2(n-1)和fib2(n-2),而计算fib2(n-1)和fib2(n-2),时按照表达式及计算法则,需先计算又必须先计算fib2(n-1),而fib2(n-1)由fib2(n-2)和fib2(n-3)计算得来,而这之中的和fib2(n-2)由fib2(n-3)和fib2(n-4)计算得来......依次类推,表面上看不出有何复杂度,但是仔细分析可知,每一个计算fib2(n)的分支都会衍生出计算直至(1)和fib(0),也就是说每个分支都要自己计算数本身到1的斐波那契数列,这样就增加了庞大且冗杂的运算量,还是以10 为例详细计算说明
图中数字代表第N个斐波那契数,图中没有全部将计算步骤画出来,但是已经足够说明问题,它的每一步计算都被分成计算前两个斐波那契数,以此类推。那么这就形成了一颗二叉树,虽然不是满二叉树,但是我们分析的是最坏时间复杂度,而且只要估算出来递归次数随N增长的趋势即可,故可以近似将它看成满二叉树,其中的节点数就是计算的次数,也就是复杂度,由公式:节点数=2^h-1(h为树的高度)可得O(2^n)。
递归算法空间复杂度分析:
递归最深的那一次所耗费的空间足以容纳它所有递归过程。递归产生的栈侦是要销毁的,所以空间也就释放了,要返回上一层栈侦继续计算+号后面的数,所以它所需要的空间不是一直累加起来的,之后产生的栈侦空间都小于递归最深的那一次所耗费的空间。
递归的深度*每次递归所需的辅助空间的个数 ,所以空间复杂度是:O(N)
6. 求二分法的时间复杂度和空间复杂度
6.1 非递归算法分析
6.2 递归算法复杂度分析
7. 扩展-----不用循环法和递归法求1+2+3+...+N(思考一种复杂度为O(1)的解法)
1 class Temp 2 { 3 public: 4 Temp(){ 5 ++N; 6 Sum += N; 7 } 8 static void Reset(){ 9 N = 0; 10 Sum = 0; 11 } 12 static int GetSum(){ 13 return Sum; 14 } 15 private: 16 static int N; 17 static int Sum; 18 }; 19 int Temp::N = 0; 20 int Temp::Sum = 0; 21 int solution_Sum(int n){ 22 Temp::Reset(); 23 Temp *a = new Temp[n]; 24 delete[]a; 25 a = 0; 26 return Temp::GetSum(); 27 } 28 int main(){ 29 cout << solution_Sum(100) << endl; 30 getchar(); 31 return 0; 32 33 }
转载于:https://www.cnblogs.com/33debug/p/6848330.html
斐波那契数与二分法的递归与非递归算法及其复杂度分析相关推荐
- 斐波那契数列(Fibonacci)递归和非递归实现
序列前9项为:0, 1, 1, 2, 3, 5, 8, 13, 21 要注意非递归的话就是那一个变量帮助存储当前下一项的值,然后依次挪动两个指针往下即可 注意如果n太大 会溢出 1 publ ...
- 用C语言实现斐波那契数
如何用C语言实现斐波那契数 首先要理解以下斐波那契数的概念 斐波那契数列指的是这样一个数列" 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 23 ...
- 斐波那契数的两种实现方式———1.递归实现,2迭代实现
对于斐波那契数,若是采用递归的算法,每个递归调用都将触发另外两个递归调用,而这两个中调用任意一个还会触发另外两个的调用.递归调用的时间复杂度O(2^N),空间复杂度为O(N),所以在计算略大的数会花费 ...
- 斐波那契数的时间复杂度、空间复杂度详解
斐波那契数:斐波那契数列指的是1.1.2.3.5.8.13.21.······这样一个数列,我们可以发现它后面的一个数是前两个数之和.而在这个数列中的数就被称为斐波那契数. 时间复杂度:时间复杂 ...
- 求斐波那契数(递归,非递归)
目录 一.斐波那契数? 二.递归实现求第n个斐波那契数 2.1代码与运行结果 2.1.1图解递归过程 三.非递归求法 3.1为什么不用递归求法 3.2非递归 一.斐波那契数? 它指的是这样的数列:1, ...
- C语言入门——求斐波那契数
斐波那契数列,又称黄金分割数列,因数学家莱昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为"兔子数列",指的是这样一个数列:1.1.2.3.5.8.13.21.34.--斐波那契数 ...
- 树上问题 ---- E. Fib-tree(斐波那契数的性质 + 暴力模拟 + 认真计算复杂度)
题目大意: 一个树是FIBFIBFIB树得是节点个数为斐波那契数,且(注意这个且)!!此外满足下面条件一个: 1.只有一个点 2.可以切一条边使得分出的两个子树都是FIBFIBFIB树. 给你一棵树, ...
- 算法----斐波那契数
題目 斐波那契数 斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 .该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就是: F(0) = 0,F(1) = 1 F ...
- 动态规划学习之三种方法解决斐波拉契数
斐波拉契数是一个很经典的问题,也会很多公司面试的考题,每个学习计算机的同学都会接触这个问题,尤其是在学习递归的时候,利用递归来解决斐波拉契数是很多教材采用的一个例子,所以很多同学一想到斐波拉契马上就会 ...
最新文章
- 2.1 线性表的定义和基本操作
- 词性标注与命名实体识别
- Could not load java.net.BindException错误解决
- 小技巧:浏览器里显示成星号的密码,忘记了该怎么办?
- java泛型程序设计——类型变量限定 + 泛型代码和虚拟机
- php企业黄页源码,PHPCMS 企业黄页模块 v9 GBK 正式版
- 找不到天隆虚拟机_玩转虚拟机,教你如何装系统
- z370支持pcie信号拆分吗_定了!AMD B550主板确认将支持PCIE4.0,多项能力接近X570
- 用PyTorch创建一个图像分类器?So easy!(Part 2)
- input框传值是怎么才能是整形_做了这些项目,到底多久才能化妆?
- 泛型类 0104 c# 1613697523
- 蚂蚁战配基金已售罄两只 累计关注人数超500万
- sass穿透 scoped 的情况下 去修改ui组件的样式
- Linux下grafana安装方式
- 解决tex中参考文献出现[S.l.: s.n.]、[S.l.]、 [s.n.]问题
- Raki的统计学习方法笔记0xF(15)章:奇异值分解
- Vue 路由的模块化
- linux 2.6.32 sdxc 补丁,在大于32GB或64GB容量的SD卡上使用NOOB安装树莓派
- 天宝DINI03/莱卡DNA03等电子水准仪原始数据处理软件使用教程
- python计算定积分_python 求定积分和不定积分示例