python中的递归

关注公众号“轻松学编程”了解更多。
文章更改后地址:传送门
间接或直接调用自身的函数被称为递归函数

间接:
def func():
otherfunc() def otherfunc():
func() 直接:
def func():
func()

递归函数必须要有收敛条件递归公式

1、递归求和

'''
使用递归求和
''' def my_sum(n):
'''
递归求和
1+2+3+...+n
:param n: int型
:return: int型
'''
# 收敛条件
if n == 1:
return 1
# 递归公式
return n + my_sum(n-1) def main():
print(my_sum(10)) if __name__ == '__main__':
main()
结果为:
55

当发生函数调用时 需要做保存现场和恢复现场的工作。

保存现场和恢复现场的工作都是利用栈(stack)来实现的。

栈是一个FILO的结构 - 栈非常的快但是它很小。

python默认栈的层数为1000层,可以使用以下方法来增加层数(不推荐)

import sys
# 比如增加层数到9999层
sys.setrecursionlimit(9999)

这样的递归不好,因为递归使用的是栈,需要用栈来保护现场和恢复现场,很耗费资源,可以使用尾递归来解决这个问题,即不回溯,直接使用最后一次的结果作为最终的结果。

2、尾递归

'''
使用递归求和
''' def my_sum(n,result=0):
'''
递归求和
1+2+3+...+n
:param n: int型
:param result: int型,上一层求得的结果,第一层递归时为0
:return: int型
'''
# 收敛条件
if n == 1:
return result +1
# 递归公式
return my_sum(n-1,result=result+n) def main():
print(my_sum(10)) if __name__ == '__main__':
main()
结果为:
55

3、递归求斐波那契数列

'''
斐波那契数列:
f(n) = 1 当n = 1,2时
f(n) = f(n-1) + f(n-2) 当n > 2时
比如: [1,1,2,3,5,8,13,21,34,55]
''' def fibonacci(n):
# 收敛条件
if n <= 2:
return 1
# 递归公式
return fibonacci(n-1) + fibonacci(n-2) def main():
print(fibonacci(10)) if __name__ == '__main__':
main()
结果为:
55

这样的递归是不好的,因为每求一层递归都要重新计算前面(n-1)层递归,开销很大,比如:

求f(9)
要先求f(8) + f(7)
而f(8)= f(7) + f(6)
f(7)=f(6) + f(5)
...

为了节省这部分重复的开销,可以使用动态规划来解决这个问题。

4、动态规划实现递归

​ 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。

​ 其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。

​ 在python中的递归,可以使用字典来代替这个表。

'''
斐波那契数列:
f(n) = 1 当n = 1,2时
f(n) = f(n-1) + f(n-2) 当n > 2时
比如: [1,1,2,3,5,8,13,21,34,55]
''' def fibonacci(n,temp={ }):
# 收敛条件
if n <= 2:
return 1
# 首先先从字典中取值
try:
return temp[n]
except KeyError:
# 如果字典中没有就先把值存进字典
temp[n] = fibonacci(n-1) + fibonacci(n-2)
return temp[n] def main():
print(fibonacci(10)) if __name__ == '__main__':
main()
结果为:
55

使用动态规划解决:

一个小孩爬阶梯,一次有3种走法:一次走1个阶梯,一次走2个阶梯,一次走3个阶梯,问如果有10个阶梯总共有多少中走法?

def walk(steps,temp={}):
if steps < 0:
return 0
elif steps == 0:
return 1
try:
return temp[steps]
except KeyError:
temp[steps] = walk(steps - 1) + walk(steps - 2) + walk(steps - 3)
return temp[steps] print(walk(10))
结果为:
274

5、使用装饰器测试递归函数用时

'''
斐波那契数列:
f(n) = 1 当n = 1,2时
f(n) = f(n-1) + f(n-2) 当n > 2时
比如: [1,1,2,3,5,8,13,21,34,55]
'''
from functools import wraps
import time def func_time(func):
# 使用@wraps后可以还原原来的函数
# 即可以使用func.__wrapped__()来去掉装饰器
@wraps(func)
def wrapper(*arg,**kwargs):
# 第一层递归才输出时间
if kwargs['level'] == 0:
start = time.perf_counter()
result = func(*arg,**kwargs)
end = time.perf_counter()
print(f'Execution Time:{end-start}s')
return result
else:
return func(*arg,**kwargs)
return wrapper @func_time
def fibonacci(n,temp={},*,level):
# 收敛条件
if n <= 2:
return 1
# 首先先从字典中取值
try:
return temp[n]
except KeyError:
level += 1
# 如果字典中没有就先把值存进字典
temp[n] = fibonacci(n-1,level=level) + fibonacci(n-2,level=level)
return temp[n] def main():
print(fibonacci(121, level=0)) fib_19 = fibonacci.__wrapped__(19,level=0)
fib_20 = fibonacci.__wrapped__(20,level=0) print(f'黄金比例:{fib_19/fib_20}') if __name__ == '__main__':
main()
结果为:
Execution Time:0.0012316425773240605s
8670007398507948658051921
黄金比例:0.6180339985218034

注意1:能用循环写的代码一定不要使用递归。

注意2:如果用递归也尽量使用尾递归(只需要递归不需要回溯)和动态规划

后记

【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!

公众号

关注我,我们一起成长~~

python中的递归的更多相关文章

  1. python中的递归问题,求圆周率

    以上面一个公式为例: import numpy as np def getPi(n): if n == 0: return np.power(-1,n)*(1.0/(2*n+1)) else: ret ...

  2. Python中解决递归限制的问题

    在做某些算法时,使用递归会出现类似下面的报错: RuntimeError: maximum recursion depth exceeded python默认的递归深度是很有限的,大概是900多的样子 ...

  3. python中使用递归实现反转链表

    反转链表一般有两种实现方式,一种是循环,另外一种是递归,前几天做了一个作业,用到这东西了. 这里就做个记录,方便以后温习. 递归的方法: class Node: def __init__(self,i ...

  4. python中的递归小实例

    #1.n! def fact(n): if n == 0: return 1 else: return n*fact(n-1)print(fact(10)) #2.斐波那契数列F(n)=F(n-1)+ ...

  5. Python中使用递归输出嵌套列表并转化为大写

  6. python中的归并排序

    本来在博客上看到用python写的归并排序的程序,然后自己跟着他写了一下,结果发现是错的,不得不自己操作.而自己对python不是非常了解所以就变百度边写,最终在花了半个小时之后就写好了. def m ...

  7. Python中递归的最大次数

    实际应用中遇到了一个python递归调用的问题,报错如下: RuntimeError: maximum recursion depth exceeded while calling a Python ...

  8. python中的迭代与递归

    遇到一个情况,需要进行递归操作,但是呢递归次数非常大,有一万多次.先不说一万多次递归,原来的测试代码是java的,没装jdk和编译环境,还是用python吧 先看下原本的java代码: public ...

  9. python中的内置函数,递归,递归文件显示(二),二分法

    1.部分内置函数 repr()显示出字符串的官方表示形式,返回一个对象的string形式 # repr 就是原封不动的输出, 引号和转义字符都不起作用 print(repr('大家好,\n \t我叫周 ...

随机推荐

  1. 18-SE-你说的都队

    文章目录 前言 建设银行app分析 招商银行app分析 中国银行app分析 工商银行app分析 总结 团队成员分工与评分 前言 18-SE-你说的都队所选项目题目为"村镇银行储蓄业务系统开发 ...

  2. Python练习题 023:比后面的人大2岁

    [Python练习题 023] 有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁.问第4个人岁数,他说比第3个人大2岁.问第三个人,又说比第2人大两岁.问第2个人,说比第一个人大两岁.最后 问 ...

  3. 手把手撸套框架-Victory框架1.0 详解

    目录 其实Victory框架1.0 在8月份就完成了,整个9月份都没有更新博客,主要还是因为松懈了. 所以,趁着国庆节的放假的时间把博客给更新一下,1.0总的来说算不得一个成熟的产品,但是拿来开发我们 ...

  4. 《C++primerplus》第6章练习题

    本来前面五题都做完了,写博客时没保存好草稿= =,写了个整合版的程序,实现前五题的关键部分. 1.定义一个叫jojo的结构,存储姓名.替身和力量值,使用动态结构数组初始化二乔.承太郎和乔鲁诺乔巴纳等人 ...

  5. Spring Cloud Config配置git私钥出错

    重装了电脑之后,重新生成了ssh key文件id_rsa和id_rsa.pub文件. 然后在配置中心的配置了私钥之后启动项目,报错如下: Reason: Property 'spring.cloud. ...

  6. 两个多维高斯分布之间的KL散度推导

    在深度学习中,我们通常对模型进行抽样并计算与真实样本之间的损失,来估计模型分布与真实分布之间的差异.并且损失可以定义得很简单,比如二范数即可.但是对于已知参数的两个确定分布之间的差异,我们就要通过推导 ...

  7. 极简 Node.js 入门 - 4.5 双工流

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  8. docker 和 k8s 调研总结

    一. docker简介 环境配置 软件开发最大的麻烦事之一,就是环境配置.用户计算机的环境都不相同,你怎么知道自家的软件,能在那些机器跑起来? 用户必须保证两件事:操作系统的设置,各种库和组件的安装. ...

  9. 租房数据分析,knn算法使用

    import numpy as np import pandas as pd import matplotlib.pyplot as plt data = pd.read_excel('jiemo.x ...

  10. Windows下使用GitStack搭建Git服务器

    Win10下使用GitStack搭建Git服务器 Git是目前世界上最先进的分布式版本控制系统(没有之一). ​ 许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别. ...