小白python进击第二周2.尾递归

递归包含两个方面的内容,一个是递归的计算过程,一个是递归过程,后者是语法上的事实而前者是概念上的计算过程,事实上在程序上我们也许是使用循环来实现的。
Python本身是不支持尾递归的(via),并且对递归次数有限制的,当递归次数超过1000次的时候,就会抛出“RuntimeError: maximum recursion depth exceeded”异常。
尾递归和一般递归不同对内存的占用
普通的递归 创建stack累积而后计算收缩 由于需要保存局部变量,栈空间则越占越多,最终导致栈溢出。
尾递归只会占用恒量的内存(和迭代一样)迭代:http://developer.51cto.com/art/201603/507935.htm
这个就是一个简单的递归函数

函数过程

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
这个曲线就代表内存占用大小的峰值,从左到右,达到顶峰,再从右到左收缩。而我们通常不希望这样的事情发生,所以使用迭代,只占据常量stack space (更新这个栈!而非扩展他)
尾递归:


理论对应调用如下:
===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120
从上面可以知道,fact_iter(x,y)中形式变量y的实际变量值是不断更新的,与普通递归对比可以看出,fact_iter(x,y)中y值不变只是在层次上加深。 尾递归是把变化的参数传递给递归函数的变量了
形式上只要最后一个return语句是单纯函数就可以写成尾递
 return  fact_iter(num-1,num*product)

尾递归的判断标准是函数运行最后一步是否调用自身,而不是是否在函数的最后一行调用自身。
好处:因为进入最后一步后不再需要参考外层函数(caller)的信息,因此没必要保存外层函数的stack,递归需要用的stack只有目前这层函数的,因此避免了栈溢出风险。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值