python 学习汇总36:递归函数(尾递归)( tcy)

递归函数(尾递归)                                                           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

猜你喜欢

转载自blog.csdn.net/tcy23456/article/details/84111639