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操作文件及文件路径实例汇总
Jan 15 Python
python查看FTP是否能连接成功的方法
Jul 30 Python
Python中的浮点数原理与运算分析
Oct 12 Python
Python使用matplotlib绘制随机漫步图
Aug 27 Python
python实现各种插值法(数值分析)
Jul 30 Python
python 并发编程 非阻塞IO模型原理解析
Aug 20 Python
python3中pip3安装出错,找不到SSL的解决方式
Dec 12 Python
django 数据库 get_or_create函数返回值是tuple的问题
May 15 Python
python开发前景如何
Jun 11 Python
详解Python 函数参数的拆解
Sep 02 Python
用Python爬取某乎手机APP数据
Jun 15 Python
python基础之模块的导入
Oct 24 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 zend解密软件绿色版测试可用
2008/04/14 PHP
php mysql数据库操作类
2008/06/04 PHP
Codeigniter通过SimpleXML将xml转换成对象的方法
2015/03/19 PHP
详解PHP中foreach的用法和实例
2016/10/25 PHP
jquery(hide方法)隐藏指定元素实例
2013/11/11 Javascript
jquery用data方法获取某个元素上的事件
2014/06/23 Javascript
Javascript实现获取窗口的大小和位置代码分享
2014/12/04 Javascript
推荐5 个常用的JavaScript调试技巧
2015/01/08 Javascript
javascript实现获取字符串hash值
2015/05/10 Javascript
AngularJS入门教程中SQL实例详解
2016/07/27 Javascript
jQuery中slidedown与slideup方法用法示例
2016/09/16 Javascript
Es6 写的文件import 起来解决方案详解
2016/12/13 Javascript
详解Node项目部署到云服务器上
2017/07/12 Javascript
nodejs实现日志读取、日志查找及日志刷新的方法分析
2019/05/20 NodeJs
使用vue for时为什么要key【推荐】
2019/07/11 Javascript
JS实现简易图片自动轮播
2020/10/16 Javascript
关于小程序优化的一些建议(小结)
2020/12/10 Javascript
[01:01:36]Optic vs paiN 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
深入理解Python3中的http.client模块
2017/03/29 Python
Django入门使用示例
2017/12/12 Python
Python利用itchat库向好友或者公众号发消息的实例
2019/02/21 Python
在python中画正态分布图像的实例
2019/07/08 Python
Python函数的默认参数设计示例详解
2019/12/01 Python
python实现一个简单RPC框架的示例
2020/10/28 Python
详解使用双缓存解决Canvas clearRect引起的闪屏问题
2019/04/29 HTML / CSS
英国假睫毛购买网站:FalseEyelashes.co.uk
2018/05/23 全球购物
C,C++的几个面试题小集
2013/07/13 面试题
幼儿园教师培训方案
2014/02/04 职场文书
签约仪式主持词
2014/03/19 职场文书
大学活动总结范文
2014/04/29 职场文书
旅游文化节策划方案
2014/06/06 职场文书
房地产经营管理专业自荐信
2014/09/02 职场文书
小学生班干部竞选稿
2015/11/20 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers
对Golang中的FORM相关字段理解
2021/05/02 Golang
Python虚拟环境virtualenv是如何使用的
2021/06/20 Python