斐波那契数列求解+尾递归

1.普通递归

这里观察f[4]的递归树代替f[10]的递归树(后者比较大,画不下)。

在这里插入图片描述

使用递归求解的时候复杂度为T(n)=T(n−1)+T(n−2)T(n)=T(n-1)+T(n-2)T(n)=T(n1)+T(n2),观察递归树,发现降速最快的是最右边每次减2,因此n2\frac{n}{2}2n层以上的部分肯定是满二叉树,因此时间复杂度肯定是Ω(2n2)\Omega(2^{\frac{n}{2}})Ω(22n)的,再加上其他节点,因此我们可以大概认为时间复杂度为O(2n)O(2^n)O(2n),空间复杂度为树的深度为O(n)O(n)O(n)

实现代码

ll Fibo(ll n)
{if(n<2) return n;return Fibo(n-1)+Fibo(n-2);
}

2.尾递归

通过改变函数的形式,能够让结果在最底层调用时直接返回。这样我们就可以在每一层函数尾调用自身来实现尾递归。因为编译器发现函数最后是尾调用(直接返回另一个函数)的时候将不会保存原函数的栈帧(因为已经执行结束),而是直接带着上一个栈帧的结果直接在原地进入下一栈帧。这样就没有递归调用时空间的额外消耗。

对于本问题,使用尾递归的话时间复杂度为O(n)O(n)O(n),空间复杂度为O(1)O(1)O(1)

ll Fibo2(ll n,ll x,ll y)//y保存当前项,调用时x=0,y=1,表示当前项为1
{if(1 == n) return y;return Fibo2(n-1, y, x+y);
}

3. 记忆化搜索

为了避免对已经计算过的值再次计算,我们用一个数组保存已经计算过的值。这样的时间复杂度将变为O(n)O(n)O(n),空间复杂度也为O(n)O(n)O(n)

ll Work3(ll n, ll* ans)
{if(n<2) return ans[n]=n;if(ans[n]) return ans[n];return ans[n]=Work3(n-1, ans)+Work3(n-2, ans);
}ll Fibo3(ll n)
{ll *ans = new ll[n+5]();ll ret = Work3(n, ans);delete[] ans;return ret;
}

4. 递推

斐波那契有递推公式:Fibo[n]=Fibo[n−1]+Fibo[n−2]Fibo[n]=Fibo[n-1]+Fibo[n-2]Fibo[n]=Fibo[n1]+Fibo[n2],因此可以用递推解决。如果记忆所有项的话,空间复杂度为O(n)O(n)O(n),如果不记忆的话空间复杂度为O(1)O(1)O(1)。时间复杂度为O(n)O(n)O(n)

ll Fibo4(ll n)
{ll *ans = new ll[n+5];ans[1]=1;for(ll i=2;i<=n;++i) ans[i]=ans[i-1]+ans[i-2];ll ret=ans[n];delete[] ans;return ret;
}

性能测试

#include <iostream>
#include <algorithm>
#include <ctime>using namespace std;typedef long long ll;
typedef ll (*FP)(ll);ll Fibo1(ll n)
{if(n<2) return n;return Fibo1(n-1)+Fibo1(n-2);
}ll Work2(ll n,ll x=0,ll y=1)//y保存当前项,调用时x=0,y=1,表示当前项为1
{if(1 == n) return y;return Work2(n-1, y, x+y);
}ll Fibo2(ll n)
{return Work2(n);
}ll Work3(ll n, ll* ans)
{if(n<2) return ans[n]=n;if(ans[n]) return ans[n];return ans[n]=Work3(n-1, ans)+Work3(n-2, ans);
}ll Fibo3(ll n)
{ll *ans = new ll[n+5]();ll ret = Work3(n, ans);delete[] ans;return ret;
}ll Fibo4(ll n)
{ll *ans = new ll[n+5];ans[1]=1;for(ll i=2;i<=n;++i) ans[i]=ans[i-1]+ans[i-2];ll ret=ans[n];delete[] ans;return ret;
}void Test(ll n,FP fp[])
{clock_t S,E;for(int i=0;i<4;++i){int T=10;double sum=0;for(int j=0;j<T;++j){S=clock();fp[i](n);E=clock();sum+=(double)(E-S)/CLOCKS_PER_SEC;}cout<<"方法"<<i+1<<"平均用时"<<sum/T<<"s"<<endl;}
}int main()
{FP fp[4]={Fibo1,Fibo2,Fibo3,Fibo4};ll n;cout<<"请输入需要查询斐波那契数列第几项:"; cin>>n;Test(n,fp);return 0;
}

运行结果

在这里插入图片描述

性能分析

可以看到后面几种方法的复杂度相差不多,但是同样是递归处理,尾递归比普通递归的复杂度明显优秀很多,所以如果可以的话应该尽量将递归变成尾递归的方式进行处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383645.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LCS最长公共子串

问题介绍 LCS问题(longest common subsequence problem)指的是求解两个字符串最长公共子序列问题。这里的子序列是可以不连续的。LCS问题广泛地出现在计算生物学中&#xff08;DNA序列、系统生成树等等&#xff09;。这里介绍如何解决LCS问题&#xff0c;以及算法的正确性证明…

操作系统【六】虚拟内存

传统存储管理方式的不足 一次性&#xff1a;作业必须一次性全部装入内存后才能开始运行。这会造成&#xff1a;当作也很大时不能全部装入内存&#xff1b;当大量作业要求运行时&#xff0c;由于内存无法容纳所有作业&#xff0c;因此只有少量作业能够运行&#xff0c;导致多道…

SQL Server【一】简介和基本概念和命令

数据结构和数据库的区别 数据库是应用软件级别研究数据的存储和操作&#xff08;主要针对磁盘上的数据&#xff09; 数据结构是在系统软件级别研究数据的存储和操作&#xff08;主要是针对内存中的数据&#xff09; 对硬盘数操作是数据库的强项&#xff0c;是数据库研究的核心…

Linux下网络socket编程——实现服务器(select)与多个客户端通信

一、关于socket通信 服务器端工作流程&#xff1a; 调用 socket() 函数创建套接字 用 bind() 函数将创建的套接字与服务端IP地址绑定调用listen()函数监听socket() 函数创建的套接字&#xff0c;等待客户端连接 当客户端请求到来之后调用 accept()函数接受连接请求&#xff0c…

SQL Server【四】

identity 主键自动增长&#xff0c;用户不需要为identity修饰的主键赋值 create table student (std_id int primary key identity(10,5),--(10,5)可以省略&#xff0c;默认为(1,1)std_name nvarchar(200) not null ) select * from student insert into student values (张三…

计算机网络【4】传输层

概述 传输层是只有主机才有的层次 传输层的功能&#xff1a; 传输层提供进程和进程之间的逻辑通信&#xff08;网络层提供主机与主机之间的逻辑通信&#xff09;复用和分用传输层对收到的报文进行差错检测 传输层有两个协议&#xff1a; 面向连接的传输层控制协议TCP&…

计算机网络【0】概述

计算机网络概念和功能 概念 是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。 计算机网络是互连的、自治&#xff08;无主从关系&#xff09;的计算机集合。 功能 数据通信&am…

计算机网络【1】物理层

物理层解决如何在连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体。 确定与传输媒体接口有关的特性 机械特性&#xff1a;定义物理连接的特性&#xff0c;如规格、接口形状、引线数目、引脚数目、排列电气特性&#xff1a;规定传输二进制位时的电…

计算机网路【2】数据链路层

结点&#xff1a;主机、路由器 链路&#xff1a;两个节点的物理通道 数据链路&#xff1a;逻辑通道&#xff0c;把实现 控制数据传输协议的硬件和软件加到链路上就构成数据链路 帧&#xff1a;链路层的协议数据单元&#xff0c;封装网络层数据报 数据链路层在物理层提供服务的…

计算机网络【5】应用层

应用层对应用程序的通信提供服务 应用层协议定义&#xff1a; 应用层的功能&#xff1a; 文件传输、访问和管理电子邮件虚拟终端查询服务和远程作业登录 重要协议&#xff1a;FTP、SMTP、POP3、HTTP、DNS 网络应用模型 客户/服务器模型&#xff08;Client/Server&#x…

操作系统【八】文件管理

文件&#xff1a;一组有意义的信息/数据集合 文件的属性&#xff1a; 文件名&#xff1a;由创建文件的用户决定文件名&#xff0c;主要是为了方便用户找到文件。同一个目录下不允许有重名文件标识符&#xff1a;一个系统内的个文件标识符唯一&#xff0c;对用户来说毫无可读性…

数据库原理及应用【六】数据库设计

数据依赖 函数依赖FD&#xff1a;一个属性或者一组属性的值可以决定另一个属性的值 多值依赖MVD&#xff1a;一个属性或者一组属性的值可以决定另一个属性的值的集合。FD是MVD的特例 符号表示&#xff1a;Name->->Course&#xff0c;课程多值依赖于姓名 连接依赖&#x…

数据库原理及应用【二】数据模型

层次模型 tree Record and fieldParent-Child relationship(PCR) 每个记录类型只有一个父节点 无法表达多对多信息 采用虚记录解决多对多 网状数据模型 系&#xff1a;主记录->属记录 主记录和属记录都可以有好多个 关系模型 表&#xff1a;table/relation 拥有更高的…

数据可视化【二】HTML+CSS+SVG+D3

HTML、CSS和SVG学习实现代码&#xff1a;https://vizhub.com/Edward-Elric233/89185eb96bc64a9d81777873a0ccd0b9 index.html <!DOCTYPE html> <html><head><title>Shapes with SVG and CSS</title><link rel"stylesheet" href&qu…

数据可视化【三】基本概念

Visualization is suitable when there is a need to augment human capabilities rather than replace people with computational decision-making methods. 当可以信赖的智能化的解决方案存在的时候&#xff0c;可视化是不必要的。 当不知道需要分析的问题是什么的时候&…

数据可视化【四】Bar Chart

Make a Bar Chart Representing a data table in JavaScriptCreating rectangles for each rowUsing linear and band scalesThe margin conventionAdding axes 以下学习内容参考博客&#xff1a;传送门 select()选择所有指定元素的第一个 selectAll()选择指定元素的全部 上…

数据库原理及应用【三】DBMS+SQL

DBMS Query LanguagesInterface and maintaining tools(GUI)APIsClass Library QL 不是图灵完备的&#xff0c;不是一种编程语言。 QL SQL是一种非过程化的查询语言。 DDL数据定义语言&#xff1a;表&#xff0c;视图QL 查询语言DML 数据操纵语言DCL 数据控制语言 Base t…

数据可视化【五】 Scatter Plot

Scatter Plot vizhub上实现的代码&#xff1a; https://vizhub.com/Edward-Elric233/53807a1b35d94329b3689081cd2ea945 https://vizhub.com/Edward-Elric233/b9647d50899a4a0e8e917f913cd0a53a https://vizhub.com/Edward-Elric233/8c6b50cd81a04f048f490f48e4fe6264 由前…

数据可视化【六】Line Chart Area Chart

Line Chart vizhub代码&#xff1a; https://vizhub.com/Edward-Elric233/094396fc7a164c828a4a8c2e13045308 实现效果&#xff1a; 这里先使用d3.line()设置每个点的x坐标和y坐标&#xff0c;然后再用这个东西设置path的d属性&#xff0c;就可以得到曲线。 const lineGen…

数据可视化【七】 更新模式

Enter 以下面这个简单的代码进行分析 const svg d3.select(svg); // svg.style(background-color, red); testconst height svg.attr(height); // equals paresFloat() const width svg.attr(width);const makeFruit type >( {type} ); //这种写法好像能够直接得到一个…