1, 递归思想

递归算法:递归(Recursion),在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。

这是官方的解释,翻译成人话就是:

  • 函数内部自己调用自己
  • 函数必须有出口

函数自己调用自己很好理解,但什么是出口呢?我们知道,递归实际上是简化嵌套for循环的一种精简算法,所以在函数内部自己调用自己的过程就是在不短的循环,并改变函数传入的参数。如果没有不再执行自己调用自己的出口,那么递归就会陷入无限循环的无底洞。

出口通常是用return或if else语句避免再调用自己。

def recursion(n):print(n, "<===1====>")if n > 0:recursion(n - 1)# 那么这就是一个出口,如果n <= 0了就会不再递归else:print(n, '<===2====>')recursion(5) # 外部调用

结果就是:


5 <===1====>
4 <===1====>
3 <===1====>
2 <===1====>
1 <===1====>
0 <===1====>
0 <===2====>  # 这个是出口,在这个时候n = 0Process finished with exit code 0

递归还有两个重要的思想,第一个我们要找到等价的运算式,也就是将大问题拆分成很多个可递归的小问题。

第二个:

  1. 递推:像上边递归实现所拆解,递归每一次都是基于上一次进行下一次的执行,这叫递推。
  2. 回溯:则是在遇到终止条件,则从最后往回返一级一级的把值返回来,这叫回溯。

听到这是不是有点懵,我们来通过下面阶乘的实例与代码实现来进一步理解这个思想。

2,递归求阶乘,代码实现与思想解析

首先先上代码:

def factorial(n):# 出口if n == 1:return 1else:return n * factorial(n-1)print(factorial(5))

这段代码求出了5的阶乘,大家先试着理解。

其中出口就是在n - 1 = 1的时候,递归就开始了回溯。

我们看一下流程图:

n * factorial(n-1)是等价表达式。红色箭头是递推的过程,从1-2-3-4;绿色箭头是回溯的过程,从a-b-c-d;紫色箭头是参数的变化。我把每一个式子都分解了一下,我们可以发现最后真正输出的是最外层的return,回溯顺序是从最底层往上返回。

如果我们改一下代码,在每一次回溯的时候输出等价表达式的值:

def factorial(n):# 出口if n == 1:return 1# 递归内层else:factor = n * factorial(n-1)print(factor)return factorprint(factorial(5))

输出:

2
6
24
120
120Process finished with exit code 0

不难发现,第一个输出的2就是流程图中的a式的值,6是b式的值,24是c式的值,120就是d式也就是最外层返回的5的阶乘了。

通过此输出,也证明了回溯过程的实现。这样我们就可以利用此思想求斐波那契数列等等等。那么递归其实也是可以用for来实现的。

# 求5的阶乘
num = 1
for i in range(1,6):num *= i
print(num)

3,栈溢出

递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出),此时程序会抛出错误:超出最大递归深度。

那么一般最大的深度是1000左右,我们可以通过sys的两个方法来设置最大深度和得到最大深度。

import sys# 得到最大的深度值
print(sys.getrecursionlimit())
# 设置最大深度为2000
sys.setrecursionlimit(2000)

4,运行速度

import sys
import time
print(sys.getrecursionlimit())
sys.setrecursionlimit(2000)
start = time.time()def factorial(n):# 出口if n == 1:return 1# 递归内层else:return n * factorial(n-1)print(factorial(1000))
print(time.time() - start)

我们通过time方法来获取运行的时间,发现大概在0.008s左右

而for循环实测在0.004秒左右,所以我们看到递归的缺点是资源占用和运行速度劣与for循环。

所以我们总结一下递归的缺点:

  1. 递归由于是函数调用自身,而函数调用是有时间和空间的消耗的--效率
  2. 递归中很多计算都是重复的,由于其本质是把一个问题分解成两个或者多个小问题,多个小问题存在相互重叠的部分,则存在重复计算--效率
  3. 调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出,强制设置最大深度会导致内存占用大--性能

优点:

  1. 简洁
  2. 在特殊情况下比for循环更加简洁,逻辑清晰。

4,建议

在使用for循环运算量并不太大时使用递归,在for循环逻辑太过于繁琐时使用递归。

Python递归思想与代码实现相关推荐

  1. Python 二分查找(涉及递归思想)

    二分查找介绍   二分查找(搜索)是一种在有序列表中查找某一特定元素的搜索算法.   首先先查找到目标列表的中间元素,如果中间元素正好是要查找的元素,则返回查找元素的索引下标,搜索结束:如果要查找的元 ...

  2. Python中的匿名函数及递归思想简析

    匿名函数 前言 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例的人,却不知道如何去学习更加高深的知识. 那么针对这三类 ...

  3. Python中匿名函数及递归思想简析(小本本记下来)

    前言: 上次咱们基本说了一下函数的定义及简单使用,想要了解的伙伴可以去看看.Python中最基本的函数及其常用用法简析(新手必备)小本本记起来 现在咱们整点进阶一些的.同样都是小白,咱也不知道实际需要 ...

  4. python匿名函数的作用_Python中的匿名函数及递归思想简析

    匿名函数 前言 上次咱们基本说了一下函数的定义及简单使用,Python中的基本函数及其常用用法简析,现在咱们整点进阶一些的.同样都是小白,咱也不知道实际需要不,但是对于函数的执行顺序以及装饰器的理解还 ...

  5. Javascript函数之深入浅出递归思想,附案例与代码!

    作者 | 浮世万千吾爱有三 责编 | Carol 来源 | CSDN 博客 递归函数的理解 1.生活中的递归 "递归"在生活中的一个典例就是"问路".如图小哥哥 ...

  6. python递归实例_python实现递归实例代码

    # 递归:在某个函数内部自己调用了自己# 递归和循环一样,必须要有退出条件.如果没有退出条件,就会无限调用自身,相当于死循环. 工具/原料 python3.6 pycharm 方法/步骤 1 def ...

  7. 十大排序算法思想和代码总结(Python版)

    Table of Contents 一.概述 二.算法简介及代码展示 1.冒泡排序($O(n^2)$) 2.简单选择排序($O(n^2)$) 3.简单插入排序($O(n^2)$) 4.堆排序($O(n ...

  8. Python递归实现快速排序

    原文:http://blog.csdn.net/zhoufen12345/article/details/53560172 快速排序(QuickSort)是对冒泡排序的一种改进: 基本思想: 通过一趟 ...

  9. 匿名函数自我调用_Python中的匿名函数及递归思想简析

    匿名函数 前言 上次咱们基本说了一下函数的定义及简单使用,Python中的基本函数及其常用用法简析,现在咱们整点进阶一些的.同样都是小白,咱也不知道实际需要不,但是对于函数的执行顺序以及装饰器的理解还 ...

最新文章

  1. 学生管理系统(C语言版)
  2. css实现左侧宽度自适应,右侧固定宽度
  3. Kafka Architecture
  4. oracle数据库迁移方案二
  5. Class-dump
  6. C#枚举数值与名称的转换
  7. Java基础- super 和 this 解析
  8. leetcode之回溯backtracing专题2
  9. dict( )、zip( )函数——python小练
  10. 大学论文的研究框架是什么?
  11. 必看!!PMP考试答题技巧
  12. 如何在移动硬盘上安装Ubuntu系统(1)
  13. matlab生成word文档
  14. 全球制造业“看上去很美”
  15. 鸿蒙之初彩蛋攻略,鸿蒙圣女 热血精灵派鸿蒙灵帝解析
  16. typora配置好smms后还是typora上传图片失败:image load failed。
  17. 浏览器是先执行js还是先加载HTML,在HTML中使用JavaScript(浏览器对js的加载机制分析)...
  18. C语言实现 IFFT 运算
  19. 经典题:用Java打印空心菱形
  20. 安装CUDA-10.0

热门文章

  1. c语言小孩分苹果问题答案忘了,大师网-小朋友学C语言(13):分苹果(小学奥数题)...
  2. 装修客户有哪些渠道可以找:装修客户资源在哪里找:装修行业怎么找客户?
  3. java redis缓存使用_redis缓存在项目中的使用
  4. Java Agent如何在IDEA里调试
  5. 传送门骑士无限物品的服务器,传送门骑士怎么无限刷资源 无限资源获得方法...
  6. 超简单超实用MySQL修改密码方法来喽
  7. Android dialog 弹窗背景图片默认为白色问题
  8. 华为无线路由器中继模式设置
  9. 通过IPV6公网远程访问路由(Padavan)
  10. 「第12章 低风险发布」