Python尾递归优化实现代码及原理详解


Posted in Python onOctober 09, 2020

在传统的递归中,典型的模式是,你执行第一个递归调用,然后接着调用下一个递归来计算结果。这种方式中途你是得不到计算结果,知道所有的递归调用都返回。 这样虽然很大程度上简洁了代码编写,但是让人很难它跟高效联系起来。因为随着递归的深入,之前的一些变量需要分配堆栈来保存。

尾递归相对传统递归,其是一种特例。在尾递归中,先执行某部分的计算,然后开始调用递归,所以你可以得到当前的计算结果,而这个结果也将作为参数传入下一次递归。这也就是说函数调用出现在调用者函数的尾部,因为是尾部,所以其有一个优越于传统递归之处在于无需去保存任何局部变量,从内存消耗上,实现节约特性。
下面以递归计算加法的实例来说明:

我们用python实现:

普通递归调用:

def recursion(n):
  if n==1:
    return n
  else:
    return n+recursion(n-1)

调用这个函数recursion(5),编译器会执行:

recursion(5)
5+recursion(4)
5+(4+recursion(3))
5+(4+(3+recursion(2)))
5+(4+(3+(2+recursion(1))))
5+(4+(3+(2+1)))
15

此处编译器会分配递归栈来保存中间结果

下来看尾递归实现:

def tail_recursion(n,total=0):
  if n==0:
    return total
  else:
    return tail_recursion(n-1, total+n)

此时,编译器做的工作:

tail_recursion(5,0)
tail_recursion(4,5)
tail_recursion(3,9)
tail_recursion(2,12)
tail_recursion(1,14)
tail_recursion(0,15)
15

你可以看到当前时刻的计算值作为第二个参数传入下一个递归,使得系统不再需要保留之前计算结果。

尾递归的优势就显而易见了。

但是python本身不支持尾递归(没有对尾递归做优化),而且对递归的次数有限制,当递归深度超过1000时,会抛出异常:

分别执行recursion(998),tail_recursion(998,0)

输出:

498501
498501

没有问题,当调用

recursion(999),tail_recursion(999,0)时,

输出:RuntimeError: maximum recursion depth exceeded

因为递归次数超出了1000

有人对此为Python的尾递归写了一个优化版本,让Python突破递归调用1000次的限制:Tail Call Optimization Decorator (Python recipe)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
使用Python的PEAK来适配协议的教程
Apr 14 Python
python中in在list和dict中查找效率的对比分析
May 04 Python
Python实现随机创建电话号码的方法示例
Dec 07 Python
python 文本单词提取和词频统计的实例
Dec 22 Python
Python简单过滤字母和数字的方法小结
Jan 09 Python
python五子棋游戏的设计与实现
Jun 18 Python
pycharm设置鼠标悬停查看方法设置
Jul 29 Python
python定时任务 sched模块用法实例
Nov 04 Python
python爬虫如何解决图片验证码
Feb 14 Python
OpenCV图像变换之傅里叶变换的一些应用
Jul 26 Python
Python办公自动化PPT批量转换操作
Sep 15 Python
pandas中pd.groupby()的用法详解
Jun 16 Python
Python hashlib模块的使用示例
Oct 09 #Python
浅析Python requests 模块
Oct 09 #Python
Python特殊属性property原理及使用方法解析
Oct 09 #Python
python GUI计算器的实现
Oct 09 #Python
Numpy实现卷积神经网络(CNN)的示例
Oct 09 #Python
Python使用socket_TCP实现小文件下载功能
Oct 09 #Python
python实现逻辑回归的示例
Oct 09 #Python
You might like
php取得字符串首字母的方法
2015/03/25 PHP
PHP查找数值数组中不重复最大和最小的10个数的方法
2015/04/20 PHP
php 可变函数使用小结
2018/06/12 PHP
php实现微信分享朋友链接功能
2019/02/18 PHP
使用PHP+Redis实现延迟任务,实现自动取消订单功能
2019/11/21 PHP
使用jQuery操作Cookies的实现代码
2011/10/09 Javascript
JavaScript中变量提升 Hoisting
2012/07/03 Javascript
html文件中jquery与velocity变量中的$冲突的解决方法
2013/11/01 Javascript
JS比较两个时间大小的简单示例代码
2013/12/20 Javascript
jquery使用jxl插件导出excel示例
2014/04/14 Javascript
浏览器窗口大小变化时使用resize事件对框架不起作用的解决方法
2014/05/11 Javascript
jQuery中offsetParent()方法用法实例
2015/01/19 Javascript
js实现同一页面多个运动效果的方法
2015/04/10 Javascript
一看就懂:jsonp详解
2015/06/01 Javascript
全面理解闭包机制
2016/07/11 Javascript
AngularJs定制样式插入到ueditor中的问题小结
2016/08/01 Javascript
ui-router中使用ocLazyLoad和resolve的具体方法
2017/10/18 Javascript
JavaScript中this关键字用法实例分析
2018/08/24 Javascript
浅谈Vue开发人员的7个最好的VSCode扩展
2021/01/20 Vue.js
Python中用format函数格式化字符串的用法
2015/04/08 Python
python实现动态数组的示例代码
2019/07/15 Python
Django 路由层URLconf的实现
2019/12/30 Python
python爬虫爬取监控教务系统的思路详解
2020/01/08 Python
python 实现Flask中返回图片流给前端展示
2020/01/09 Python
Python中sorted()排序与字母大小写的问题
2020/01/14 Python
python右对齐的实例方法
2020/07/05 Python
Python如何发送与接收大型数组
2020/08/07 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
基于Python 函数和方法的区别说明
2021/03/24 Python
岳父生日宴会答谢词
2014/01/13 职场文书
《落花生》教学反思
2014/02/25 职场文书
2015年党建工作目标责任书
2015/05/08 职场文书
解除处分决定书
2015/06/25 职场文书
jquery插件实现悬浮的菜单
2021/04/24 jQuery
vue项目两种方式实现竖向表格的思路分析
2021/04/28 Vue.js
python中pycryto实现数据加密
2022/04/29 Python