详解python使用递归、尾递归、循环三种方式实现斐波那契数列
作者:Together_CZ 发布时间:2022-06-22 13:44:49
在最开始的时候所有的斐波那契代码都是使用递归的方式来写的,递归有很多的缺点,执行效率低下,浪费资源,还有可能会造成栈溢出,而递归的程序的优点也是很明显的,就是结构层次很清晰,易于理解
可以使用循环的方式来取代递归,当然也可以使用尾递归的方式来实现。
尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量. 直接让被调用的函数返回时越过调用者, 返回到调用者的调用者去。尾递归就是把当前的运算结果(或路径)放在参数里传给下层函数,深层函数所面对的不是越来越简单的问题,而是越来越复杂的问题,因为参数里带有前面若干步的运算路径。尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。直接递归的程序中需要保存之前n步操作的所有状态极其耗费资源,而尾递归不需要,尾部递归是一种编程技巧。如果在递归函数中,递归调用返回的结果总被直接返回,则称为尾部递归。尾部递归的函数有助将算法转化成函数编程语言,而且从编译器角度来说,亦容易优化成为普通循环。这是因为从电脑的基本面来说,所有的循环都是利用重复移跳到代码的开头来实现的。如果有尾部归递,就只需要叠套一个堆栈,因为电脑只需要将函数的参数改变再重新调用一次
为了加深对尾递归、递归和循环的对比,这里以斐波那契数列的实现举例:
#!usr/bin/env python
#encoding:utf-8
'''''''
__Author__:沂水寒城
功能:尾递归
'''
import time
def Fib_recursion(num):
'''''
直接使用递归法求解斐波那契数量的第num个数字
'''
if num<2:
return num
return Fib_recursion(num-1)+Fib_recursion(num-2)
def Fib_tail_recursion(num,res,temp):
'''''
使用尾递归法求解斐波那契数量的第num个数字
'''
if num==0:
return res
else:
return Fib_tail_recursion(num-1, temp, res+temp)
def Fib_circle(num):
'''''
直接使用循环来求解
'''
a=0
b=1
for i in range(1,num):
c=a+b
a=b
b=c
return c
if __name__ == '__main__':
num_list=[5,10,20,30,40,50]
for num in num_list:
start_time=time.time()
print Fib_recursion(num)
end_time=time.time()
print Fib_tail_recursion(num,0,1)
end_time2=time.time()
print Fib_circle(num)
end_time3=time.time()
print '正在求解的斐波那契数字下标为%s' %num
print '直接递归耗时为 :', end_time-start_time
print '尾递归调用耗时为:', end_time2-end_time
print '直接使用循环耗时为:', end_time3-end_time2
结果如下:
5
5
5
正在求解的斐波那契数字下标为5
直接递归耗时为 : 6.38961791992e-05
尾递归调用耗时为: 2.31266021729e-05
直接使用循环耗时为: 1.97887420654e-05
55
55
55
正在求解的斐波那契数字下标为10
直接递归耗时为 : 6.60419464111e-05
尾递归调用耗时为: 3.31401824951e-05
直接使用循环耗时为: 1.8835067749e-05
6765
6765
6765
正在求解的斐波那契数字下标为20
直接递归耗时为 : 0.00564002990723
尾递归调用耗时为: 3.09944152832e-05
直接使用循环耗时为: 2.09808349609e-05
832040
832040
832040
正在求解的斐波那契数字下标为30
直接递归耗时为 : 0.39971113205
尾递归调用耗时为: 1.69277191162e-05
直接使用循环耗时为: 1.19209289551e-05
102334155
102334155
102334155
正在求解的斐波那契数字下标为40
直接递归耗时为 : 39.0365440845
尾递归调用耗时为: 2.19345092773e-05
直接使用循环耗时为: 1.78813934326e-05
12586269025
12586269025
12586269025
正在求解的斐波那契数字下标为50
直接递归耗时为 : 4915.68643498
尾递归调用耗时为: 2.19345092773e-05
直接使用循环耗时为: 2.09808349609e-05
画图图表更加清晰地可以看到差距:
因为差距太大,导致尾递归和循环的两种方式的时间增长几乎是水平线,而直接递归的时间增长接近90度。
这一次,感觉自己好有耐心,一直就在那里等着程序出结果,可以看到三者的时间对比状况,很明显的:直接递归的时间增长的极快,而循环的性能还要优于尾递归,这就告诉我们尽量减少递归的使用,使用循环的方式代替递归无疑是一种提高程序运行效率的方式。
来源:http://blog.csdn.net/Together_CZ/article/details/76216239


猜你喜欢
- 前言Hello!大家好,有好几天没有跟大家见面咯~不知道大家是否在等待《小玩意儿》专栏的更新呢上一篇的文章【老师见打系列】:我只是写了一个自
- FLV在线转换,是目前主流播客网上通用的一种视频解决方案需要用到的组件 ASPExecmencoderffmpeg.exe第一步骤: 在线转
- 一. 抛出异常Python用异常对象(exception object)表示异常情况,遇到错误后,会引发异常。如果异常对象并未被处理或捕捉,
- 在select语句中可以使用groupby子句将行划分成较小的组,然后,使用聚组函数返回每一个组的汇总信息,另外,可以使用having子句限
- 在本节中,我们将详细介绍 Python 标准库中的 json 模块。JSON(JavaScript Objec
- 互联网时代数据是 * 式增长,我们常常需要把结构化数据和非结构化数据(如文档,演示文稿,视频,音频,图像)存储在一起。通常有几种方案: 1。在
- 图片数据一般有两种情况:1、所有图片放在一个文件夹内,另外有一个txt文件显示标签。2、不同类别的图片放在不同的文件夹内,文件夹就是图片的类
- 1. 抓取街拍图片街拍图片网址2. 分析街拍图片结构keyword: 街拍pd: atlasdvpf: pcaid: 4916page_nu
- 关于选课程序,最近着实有点忙,没机会复习os、pickle两部分模块,所以数据储存和字典读取成为了一个问题,大致原理知道,但是具体操作可能还
- 1、获取秒级时间戳与毫秒级时间戳、微秒级时间戳import timeimport datetimet = time.time()print
- 首先,需要简单的了解一下爬虫,尽可能简单快速的上手,其次,需要了解的是百度的API的接口,搞定这个之后,最后,按照官方给出的demo,然后写
- Google Chrome 的发布,使我们更加的注重基于 WebKit 核心的浏览器的表现情况,但我们很多时候“不小心”就会出现
- GUI编程之 Pack、Place、Grid的区别本文讲述如何使用 tkinter 的布局管理 (被称作 layout managers 或
- 相关代码如下: 1. 创建sequence: 代码如下:CREATE SEQUENCE SEQU_DATA_DATAINFO IN
- 案例解析这个问题描述起来有点违反直觉,要执行一个文件难道不应该需要可执行权限吗?让我们先来看一个例子:# module1.pydef tes
- 导言:在前面的教程我们阐述了应用程序处理二进制数据的2种模式,以及使用FileUpload 控件从浏览器向服务器文件系统上传文件。当文件上传
- 引言目前Python2和Python3存在版本上的不兼容性,这里将列举dict中的问题之一。下面话不多说,来看看详细的介绍:1. Pytho
- 一、简介Paramiko模块是基于Python实现的SSH远程安全连接,用于SSH远程执行命令、文件传输等功能。安装模块默认Python没有
- 前言在日常工作中,可能需要结合网上现在的一些API或者公司提供的数据接口来得到相应的数据或者实现对应的功能。因此API的调用和数据接口的访问
- 本文实例分析了Go语言中关闭带缓冲区的频道。分享给大家供大家参考。具体分析如下:Go语言提供了两种频道,带缓冲区和不带缓冲区的。不带缓冲区的