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学习笔记之os模块使用总结
Nov 03 Python
Python编写百度贴吧的简单爬虫
Apr 02 Python
Python3写入文件常用方法实例分析
May 22 Python
基于Python 装饰器装饰类中的方法实例
Apr 21 Python
Python中的 is 和 == 以及字符串驻留机制详解
Jun 28 Python
python lambda表达式在sort函数中的使用详解
Aug 28 Python
pytorch之添加BN的实现
Jan 06 Python
Python 面向对象之类class和对象基本用法示例
Feb 02 Python
Python打包模块wheel的使用方法与将python包发布到PyPI的方法详解
Feb 12 Python
Python连接mysql方法及常用参数
Sep 01 Python
Django用内置方法实现简单搜索功能的方法
Dec 18 Python
从Pytorch模型pth文件中读取参数成numpy矩阵的操作
Mar 04 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中使用Oracle数据库(2)
2006/10/09 PHP
php读取mysql的简单实例
2014/01/15 PHP
PHP访问数据库集群的方法小结
2016/03/14 PHP
php使用CURL模拟GET与POST向微信接口提交及获取数据的方法
2016/09/23 PHP
关于PHP虚拟主机概念及如何选择稳定的PHP虚拟主机
2018/11/20 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
一个js实现的所谓的滑动门
2007/05/23 Javascript
js 图片随机不定向浮动的实现代码
2013/07/02 Javascript
js中split函数的使用方法说明
2013/12/26 Javascript
JSON与XML优缺点对比分析
2015/07/17 Javascript
javascript实现很浪漫的气泡冒出特效
2020/09/05 Javascript
利用JQuery直接调用asp.net后台的简单方法
2016/10/27 Javascript
JavaScript学习笔记之函数记忆
2017/09/06 Javascript
vue+elementUI实现图片上传功能
2019/08/20 Javascript
Vue路由之JWT身份认证的实现方法
2019/08/26 Javascript
JS检索下拉列表框中被选项目的索引号(selectedIndex)
2019/12/17 Javascript
简单了解常用的JavaScript 库
2020/07/16 Javascript
[06:24]DOTA2 2015国际邀请赛中国区预选赛第二日TOP10
2015/05/27 DOTA
[01:53]2016完美“圣”典风云人物:Maybe专访
2016/12/05 DOTA
如何用C代码给Python写扩展库(Cython)
2019/05/17 Python
matlab 计算灰度图像的一阶矩,二阶矩,三阶矩实例
2020/04/22 Python
基于python实现坦克大战游戏
2020/10/27 Python
Kathmandu新西兰官网:新西兰户外运动品牌
2019/07/27 全球购物
JBL美国官方商店:扬声器、耳机等
2019/12/01 全球购物
.NET是怎么支持多种语言的
2015/02/24 面试题
硅酸盐工业控制专业应届生求职信
2013/11/02 职场文书
十八大演讲稿
2014/05/22 职场文书
爱祖国爱家乡演讲稿
2014/09/02 职场文书
电子商务专业求职信范文
2015/03/19 职场文书
门店店长岗位职责
2015/04/14 职场文书
企业年会祝酒词
2015/08/11 职场文书
教师正风肃纪心得体会
2016/01/15 职场文书
2016年大学光棍节活动总结
2016/04/05 职场文书
优秀大学生申请书
2019/06/24 职场文书
Python基础详解之邮件处理
2021/04/28 Python
vue3种table表格选项个数的控制方法
2022/04/14 Vue.js