什么是递归?

递归,就是函数在运行的过程中调用自己。

代码示例

def recursion(n):

    print(n)
recursion(n+) recursion()  

出现的效果就是,这个函数在不断的调用自己,每次调用就n+1,相当于循环了。

可是为何执行了900多次就出错了呢?还说超过了最大递归深度限制,为什么要限制呢?

通俗来讲,是因为每个函数在调用自己的时候 还没有退出,占内存,多了肯定会导致内存崩溃。

本质上讲呢,在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

递归的特点

让我们通过现象来看本质, 下面是是用递归写的,让10不断除以2,直到0为止。

打印的是1, 然后最里层的函数就结束了,结束后会返回到之前调用它的位置。即上一层,上一层打印的是2,再就是5,再就是10,即最外层函数,然后结束,总结,这个递归就是一层层进去,还要一层层出来。

通过上面的例子,我们可以总结递归几个特点:

  1. 必须有一个明确的结束条件,要不就会变成死循环了,最终撑爆系统
  2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  3. 递归执行效率不高,递归层次过多会导致栈溢出

递归有什么用呢?

可以用于解决很多算法问题,把复杂的问题分成一个个小问题,一一解决。

比如求斐波那契数列、汉诺塔、多级评论树、二分查找、求阶乘等。用递归求斐波那契数列、汉诺塔 对初学者来讲可能理解起来不太容易,所以我们用阶乘和二分查找来给大家演示一下。

求阶乘

任何大于1的自然数n阶乘表示方法: 
n!=1×2×3×……×n 
或 
n!=n×(n-1)!

即举例:4! = 4x3x2x1 = 24

用递归代码来实现

def factorial(n):

    if n == : #是0的时候,就运算完了
return
return n * factorial(n-) # 每次递归相乘,n值都较之前小1 d = factorial()
print(d)

2分查找

在一个已排序的数组data_set中,使用二分查找n,假如这个数组的范围是[low...high],我们要的n就在这个范围里。查找的方法是拿low到high的正中间的值,我们假设是mid,来跟n相比,如果mid>n,说明我们要查找的n在前数组data_set的前半部,否则就在后半部。无论是在前半部还是后半部,将那部分再次折半查找,重复这个过程,知道查找到n值所在的地方。

data_set = list(range())

def b_search(n,low,high,d):

    mid = int((low+high)/) # 找到列表中间的值
if low == high:
print("not find")
return
if d[mid] > n: # 列表中间值>n, 代数要找的数据在左边
print("go left:",low,high,d[mid])
b_search(n,low,mid,d) # 去左边找
elif d[mid] < n: # 代数要找的数据在左边
print("go right:",low,high,d[mid])
b_search(n,mid+,high,d) # 去右边找
else:
print("find it ", d[mid]) b_search(, ,len(data_set),data_set)
go right:
go right:
go right:
go right:
go right:
go right:
not find

最多将会操作7次,其实因为每一次我们都抛掉当前确定的区间的一半的区间作为不可能解部分,那么相当于求最多操作次数,就是在区间内,最多将有多少个一半可以抛去、那么就是将100一直除以2,直到不能除为止。

那么这个运算过程,其实就是相当于求了一个log2(100)≈7。

补充:

在讲特性时,我们说递归效率不高,因为每递归一次,就多了一层栈,递归次数太多还会导致栈溢出,这也是为什么python会默认限制递归次数的原因。但有一种方式是可以实现递归过程中不产生多层栈的,即尾递归,

尾递归

在函数最尾部有return,return值是递归形式调用,且返回值与上一层函数无任何依赖。

尾递归例子

def calc(n):
print(n - )
if n > -:
return calc(n-)

我们之前求的阶乘是尾递归么?

def factorial(n):

    if n == : #是0的时候,就运算完了
return
return n * factorial(n-) # 每次递归相乘,n值都较之前小1 d = factorial()
print(d)

上面的这种递归计算最终的return操作是乘法操作。所以不是尾递归。因为每个活跃期的返回值都依赖于用n乘以下一个活跃期的返回值,因此每次调用产生的栈帧将不得不保存在栈上直到下一个子调用的返回值确定。

Python3-递归函数的更多相关文章

  1. python3 递归函数return返回None

    今天写了一个函数,执行之后打印出来的结果是None,不明白,之后百度了一下,这里记一下过程,免得之后再踩坑 #!/usr/bin/python3# -*- coding:utf-8 -*- def b ...

  2. 第十一天python3 递归函数

    递归Recursion 函数直接或者间接调用自身就是递归: 递归需要有边界条件,递归前进段.递归返回段: 递归一定要有边界条件: 当边界条件不满足的时候,递归前进: 当边界条件满足的时候,递归返回: ...

  3. Python3学习(二)-递归函数、高级特性、切片

    ##import sys ##sys.setrecursionlimit(1000) ###关键字参数(**关键字参数名) ###与可变参数不同的是,关键字参数可以在调用函数时,传入带有参数名的参数, ...

  4. Python自学笔记-递归函数(来自廖雪峰的官网Python3)

    感觉廖雪峰的官网http://www.liaoxuefeng.com/里面的教程不错,所以学习一下,把需要复习的摘抄一下. 以下内容主要为了自己复习用,详细内容请登录廖雪峰的官网查看.   递归函数 ...

  5. Python3练习题 022:用递归函数反转字符串

    方法一 str = input('请输入若干字符:')   def f(x):     if x == -1:         return ''     else:         return s ...

  6. 4.6 Python3 进阶 - 递归函数

    >>返回主目录 源码 # 定义及特性 # 简单递归思维练习,求和:1+2+3+-+100 # 思路:sum(100) = sum(99) + 100 # sum(99) = sum(98) ...

  7. Python 第四篇:生成器、迭代器、装饰器、递归函数与正则表达式

    一:生成器:Generator,可以理解为是一种一个函数产生一个迭代器,而迭代器里面的数据是可以通过for循环获取的,那么这个函数就是一个生成器,即生成器是有函数生成的,创建生成器使用()表示,比如g ...

  8. 汉诺塔python3函数编写和过程分析

    !/usr/bin/env python3 -- coding: utf-8 -- 利用递归函数计算阶乘 N! = 1 * 2 * 3 * ... * N def fact(n): if n == 1 ...

  9. 廖雪峰Python3笔记

    主要复习过一遍 简介 略 安装 略 *** 第一个Python程序 第一行的注释: # _*_ coding: utf-8 _*_ #!/usr/bin/env python3 print() 可以接 ...

  10. 14 python初学(高阶函数 递归函数 内置函数)

    高阶函数:1.  函数名是一个变量,函数名可以进行赋值 2. 函数名可以作为函数参数,还可以作为函数返回值(函数名称作为函数返回值时返回的是:函数的地址:print 这个返回值的调用相当于执行这个函数 ...

随机推荐

  1. bzoj1875 边点互换+矩乘

    https://www.lydsy.com/JudgeOnline/problem.php?id=1875 题意 HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走 ...

  2. jupyter notebook的安装与使用

    一.jupyter notebool介绍 Jupyter Notebook是Ipython的升级版,而Ipython可以说是一个加强版的交互式 Shell,也就是说,它比在terminal里运行pyt ...

  3. OS + Linux nmon / nmon analyser / nmon_analyser_v52_1.zip

    s nmon_analyser_v52_1.zip https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/Pow ...

  4. weblogic优化(内存、线程数和启动速度)

    一.为服务分配内存 1.一般如果服务所需的内存不一样,需要单独指定的话,我们是通过拷贝startWebLogic.sh文件,拷贝为startNode.sh(名字随意) 2.然后在startNode.s ...

  5. python django基础四 ORM简介

    ORM,全称是object relation mapping.翻译过来,就是对象关系映射. 主要来学习MySQL操作,MySQL是一个软件.它的优点:1.免费 2.开源 pymysql,就是Mysql ...

  6. IDEA之debug的坑

    IDEA是一款火热的开发工具.debug谁都会,很简单?NO 一次不正常的关机,导致第二条上班debug失效,浪费两个小时.特做此记录. 1.如下图点击View Breakpoints进入可以到你设置 ...

  7. vue input添加回车触发

    普通vue input @keyup.enter="onSubmit" element el-input @keyup.enter.native="onSubmit&qu ...

  8. 记一次解决非法参数DDoS攻击的实践

    起因 线上项目突然遭到大量的非法参数攻击,由于历史问题,之前的代码从未对请求参数进行校验. 导致大量请求落到了数据访问层,给应用服务器和数据库都带来了很大压力. 针对这个问题,只能对请求真正到Cont ...

  9. Struts2的初级应用

    做一个登录注册 1.把Struts2框架的必须包导入到项目中(http://struts.apache.org/) 2.web.xml <?xml version="1.0" ...

  10. Retrofit GreenDao开发中遇到的坑

    持续更新中1.使用@FormUrlEncoded的话,服务端需要使用Request.Form,如果不使用@FormUrlEncoded本地需要由 @FieldMap Map<String, Ob ...