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创建文件和追加文件内容实例
Oct 21 Python
python中input()与raw_input()的区别分析
Feb 27 Python
Python编程实现数学运算求一元二次方程的实根算法示例
Apr 02 Python
Python 实现购物商城,含有用户入口和商家入口的示例
Sep 15 Python
Python中使用支持向量机(SVM)算法
Dec 26 Python
python实现画一颗树和一片森林
Jun 25 Python
matplotlib.pyplot绘图显示控制方法
Jan 15 Python
Python函数和模块的使用总结
May 20 Python
python实现多进程按序号批量修改文件名的方法示例
Dec 30 Python
python 通过邮件控制实现远程控制电脑操作
Mar 16 Python
Python Django中的STATIC_URL 设置和使用方式
Mar 27 Python
Jupyter notebook设置背景主题,字体大小及自动补全代码的操作
Apr 13 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
apache配置虚拟主机的方法详解
2013/06/17 PHP
yii插入数据库防并发的简单代码
2017/05/27 PHP
数理公式,也可以这么唯美
2021/03/10 无线电
用JAVASCRIPT如何给<textarea></textarea>赋值
2007/04/20 Javascript
javascript利用控件对windows的操作实现原理与应用
2012/12/23 Javascript
Jquery实现点击切换图片并隐藏显示内容(2种方法实现)
2013/04/11 Javascript
JQuery操作三大控件(下拉,单选,复选)的方法
2013/08/06 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
2014/02/12 Javascript
js控制浏览器全屏示例代码
2014/02/20 Javascript
对 jQuery 中 data 方法的误解分析
2014/06/18 Javascript
Ionic + Angular.js实现验证码倒计时功能的方法
2017/06/12 Javascript
JS按钮闪烁功能的实现代码
2017/07/21 Javascript
javascript算法之二叉搜索树的示例代码
2017/09/12 Javascript
vue 使用ref 让父组件调用子组件的方法
2018/02/08 Javascript
浅谈vue父子组件怎么传值
2018/07/21 Javascript
小程序实现授权登陆的解决方案
2018/12/02 Javascript
vue项目中mock.js的使用及基本用法
2019/05/22 Javascript
ES6学习笔记之let与const用法实例分析
2020/01/22 Javascript
ES6扩展运算符和rest运算符用法实例分析
2020/05/23 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
vue 基于abstract 路由模式 实现页面内嵌的示例代码
2020/12/14 Vue.js
Python学习笔记整理3之输入输出、python eval函数
2015/12/14 Python
Python编程实现生成特定范围内不重复多个随机数的2种方法
2017/04/14 Python
python利用百度AI实现文字识别功能
2018/11/27 Python
Python代码打开本地.mp4格式文件的方法
2019/01/03 Python
python调用并链接MATLAB脚本详解
2019/07/05 Python
Python正则表达式匹配日期与时间的方法
2019/07/07 Python
Python3中的最大整数和最大浮点数实例
2019/07/09 Python
Python使用docx模块实现刷题功能代码
2020/02/13 Python
JustFab加拿大:女鞋、靴子、手袋和服装在线
2018/05/18 全球购物
《金钱的魔力》教学反思
2014/02/24 职场文书
2015年社区综治工作总结
2015/04/21 职场文书
小学生反邪教心得体会
2016/01/15 职场文书
使用jpa之动态插入与修改(重写save)
2021/11/23 Java/Android
Appium中scroll和drag_and_drop根据元素位置滑动
2022/02/15 Python
python数字图像处理实现图像的形变与缩放
2022/06/28 Python