赞
踩
递归函数(尾递归) 2018/11/15
- 用途:
- 递归函数常用于检索大量数据,替代for循环。
1.递归深度设置:
- sys.getrecursionlimit() #返回当前最多的递归深度默认3000 #ipython
- sys.setrecursionlimit(1000) #设置递归深度
- 注意:
- 不能用在生成器函数和协程中
-
- 函数式编程并未通过 while 或者 for 声明提供迭代功能,同样也未提供状态更新。
- 任何可迭代的代码都可以转换为可递归的代码
2.实例1:定义阶乘函数factorial ;递归实现
- def factorial(n):
- if n<=1:
- return 1
- else:
- return n * factorial(n-1)
实例2:定义阶乘factorial lambda表达式;递归实现
factorial1=(lambda n: 1 if n <= 1 else n * factorial1(n-1))#运行时间稍快于上面
测试 :
- sys.setrecursionlimit(3000)#若设定3000,下面n<=2999
- a=factorial(1) #1
- print(a)
- a=factorial(5) #120
- print(a)
- a=factorial(6) #720
- print(a)
实例3:定义斐波那契数;递归实现
- def fibonacci(n):
- if n==1 or n==2:
- return 1
- return fibonacci(n-1)+fibonacci(n-2)
实例4:定义斐波那契数;lambda递归实现
- fibonacci = (lambda x , x1=1,x2=0:
- x2 if x == 0 else fibonacci (x - 1, x1 + x2, x1))
测试 :
- a=fibonacci(1) #1
- print(a)
- a=fibonacci(5) #5
- print(a)
- a=fibonacci(6) #8
- print(a)
3.尾递归
- 尾递归基于函数的尾调用, 每一级调用直接返回函数的返回值更新调用栈,而不用创建新的调用栈,
- 类似迭代的实现,时间和空间上均优化了一般递归!
- python不支持尾递归。解决办法先定义一个修饰符,然后在定义尾递归函数。
-
- 参考:
- http://www.open-open.com/lib/view/open1480494663229.html
尾递归定义实例:
- 阶乘实例函数修改为支持尾递归,不需要在设置递归深度
- 如果无修饰符那么n的能用数据范围为2899(假设你设定递归深度为3000的话)
- @tail_call_optimized #修饰符函数在下面定义
- def factorial(n,acc=1):#阶乘
- if n==0:
- return acc
- else:
- return n*factorial(n-1,n*acc)
测试:
- def factorial(n):#普通阶乘递归定义,用于测试比对
- if n<=1:
- return 1
- else:
- return n * factorial(n-1)
- n=2999
- for i in range(n):
- if factorial(i)==factorial1(i):
- # print('ok')
- pass
- else:
- print('ng')
- print('end')
4.备注:
@tail_call_optimized的定义 :
4.1.异常类定义
- class TailRecurseException(Exception):
- def __init__(self, args, kwargs):
- self.args = args
- self.kwargs = kwargs
4.2.尾递归修饰符函数 :
def tail_call_optimized(g): """ 这个函数用尾调用优化来修饰函数。它通过抛出一个异常(如果是它自己的祖父母)来实现这一点, 并捕获这样的异常来伪造尾调用优化。如果修饰函数在非尾上下文中递归,则此函数将失败。 """ def func(*args, **kwargs): '''' 函数默认第一层递归是父调用,对于尾递归, 不希望产生新的函数调用(即:祖父调用), 所以这里抛出异常, 拿到参数, 退出被修饰函数的递归调用栈 ''' f = sys._getframe() if f.f_back and f.f_back.f_back and f.f_back.f_back.f_code == f.f_code: raise TailRecurseException(args, kwargs)# 抛出异常 else: while 1: try: return g(*args, **kwargs) except TailRecurseException as e: args = e.args # 捕获异常, 拿到参数, 退出被修饰函数的递归调用栈 kwargs = e.kwargs func.__doc__ = g.__doc__ return func
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。