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从有道词典网页获取单词翻译
Jul 03 Python
Windows下Python3.6安装第三方模块的方法
Nov 22 Python
Python动态参数/命名空间/函数嵌套/global和nonlocal
May 29 Python
python实现雪花飘落效果实例讲解
Jun 18 Python
使用python 写一个静态服务(实战)
Jun 28 Python
python输入多行字符串的方法总结
Jul 02 Python
Python爬虫 批量爬取下载抖音视频代码实例
Aug 16 Python
python numpy中cumsum的用法详解
Oct 17 Python
学Python 3的理由和必要性
Nov 19 Python
python-numpy-指数分布实例详解
Dec 07 Python
使用Pycharm在运行过程中,查看每个变量的操作(show variables)
Jun 08 Python
Pycharm中使用git进行合作开发的教程详解
Nov 17 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做推送服务端实现ios消息推送
2013/07/01 PHP
php统计数组元素个数的方法
2015/07/02 PHP
浅谈php的优缺点
2015/07/14 PHP
PHP中Session和Cookie是如何操作的
2015/10/10 PHP
Function.prototype.bind用法示例
2013/09/16 Javascript
node.js require() 源码解读
2015/12/13 Javascript
JS遍历数组及打印数组实例分析
2016/01/21 Javascript
vue实现a标签点击高亮方法
2018/03/17 Javascript
Vue中在新窗口打开页面及Vue-router的使用
2018/06/13 Javascript
vue实现在一个方法执行完后执行另一个方法的示例
2018/08/25 Javascript
如何在Vue.js中实现标签页组件详解
2019/01/02 Javascript
JavaScript常见鼠标事件与用法分析
2019/01/03 Javascript
vue数据初始化initState的实例详解
2019/04/11 Javascript
vue Treeselect 树形下拉框:获取选中节点的ids和lables操作
2020/08/15 Javascript
Python中每次处理一个字符的5种方法
2015/05/21 Python
Python 模块EasyGui详细介绍
2017/02/19 Python
python使用tkinter实现简单计算器
2018/01/30 Python
浅谈python实现Google翻译PDF,解决换行的问题
2018/11/28 Python
Django异步任务之Celery的基本使用
2019/03/23 Python
python实现宿舍管理系统
2019/11/22 Python
Python自定义sorted排序实现方法详解
2020/09/18 Python
python pip如何手动安装二进制包
2020/09/30 Python
HTML5的自定义属性data-*详细介绍和JS操作实例
2014/04/10 HTML / CSS
AmazeUI 单选框和多选框的实现示例
2020/08/18 HTML / CSS
存储过程和函数的区别
2013/05/28 面试题
博士研究生自我鉴定范文
2013/12/04 职场文书
高中生毕业自我鉴定范文
2013/12/22 职场文书
课程设计心得体会
2013/12/28 职场文书
校长先进事迹材料
2014/02/01 职场文书
2014学雷锋活动总结
2014/03/09 职场文书
农村党员一句话承诺
2014/05/30 职场文书
领导干部“四风”查摆问题个人整改措施
2014/10/28 职场文书
政协工作总结2015
2015/05/20 职场文书
汉字听写大会观后感
2015/06/12 职场文书
小学体育教学随笔
2015/08/14 职场文书
厉害!这是Redis可视化工具最全的横向评测
2021/07/15 Redis