Python 函数进阶-递归函数

递归函数

什么是递归函数

如果函数可以调用自身,则该函数是递归函数。

[En]

If a function can call itself, then the function is a recursive function.

递归就是去,返回就是返回,递归就是往回走的过程。

[En]

Recursion is to go, return is to return, and recursion is the process of going back.

Python 函数进阶-递归函数

递归函数的条件

一般来说,递归需要 边界条件,整个递归的结构中要有 递归前进段递归返回段。当边界条件不满足,递归前进,反之递归返回。就是说递归函数一定需要有边界条件来控制递归函数的前进和返回。

定义一个简单的递归函数

定义一个函数
def recursion(num):

    print(num)
    if num == 0:
        return 'ok'

    # 这个函数在自己的作用域中调用自己,这个函数就是一个递归函数
    recursion(num-1)

recursion(10)
"""
结果:
10
9
8
7
6
5
4
3
2
1
0
"""

代码解析

我们使用参数10执行这个函数,但是在执行这个函数的过程中,我们再次调用自己,所以现在这个函数将进入第二次第一次调用自己的过程,第一次调用将被暂时阻止。

[En]

We execute this function with an argument of 10, but during the execution of this function, we call ourselves again, so now this function will go into the process of first calling itself for the second time, and the first call will be temporarily blocked.

第二次调用的时候,num-1,参数就变成了9,继续执行,然后就又执行到了调用自己的代码中,现在就会执行第三次调用的过程中,第二次的调用也阻断了;

这就是 递 的过程;

…………

第十一次调用的时候,num-1,层层的嵌套,参数就变成了0,就符合了作用域中的 if num == 0的条件判断式,第十一次的调用就没有再执行到了调用自己的代码,而是彻彻底底的执行完成了 ,然后代码的执行就又回到了第十次的函数调用中。

第十次的函数调用阻断的时候是执行到了 recursion(num-1),但是这一行代码执行完了,也就是第十一次调用执行完了,并且后面也没有任何代码,所以第十次调用也结束了,然后就回到了第九次调用;然后第八次;再就是第七次,一直到第一次结束,整个函数的执行就结束了;

这就是 归 的过程。

Python 函数进阶-递归函数

内存栈区堆区

堆栈空间是我们通常所说的STACK,STACK是一个先入后出的空间,正如我们在上面的例子中所说的,我们首先执行函数的第一个调用,但第一个调用由最后一个执行释放,第11个调用是由第一个执行释放的最后一个调用。与堆栈空间的概念相反的是队列空间,它是一个先进、先出、先入、先出的空间,就像我们平时排队一样,第一个队列会比后一个队列先买票,然后当我们学习并发时,我们会详细讨论队列的概念。

[En]

Stack space is what we often call stack, stack is a space with go and go, first in and then out, as we said in the above example, we first execute the first call of the function, but the first call is released by the last execution, and the eleventh call is the last call, which is released by the first execution. Contrary to the concept of stack space is the queue space, which is a first-in, first-out, first-in, first-out space, just as we usually queue up, the first queue will buy tickets first than the later, and then when we learn concurrency, we will talk about the concept of queue in detail.

单独堆栈是一种数据结构,堆栈是先进先出的数据结构,堆排序后是树状数据结构。

[En]

A separate stack is a data structure, the stack is a first-in-first-out data structure, and the heap is a tree-like data structure after sorting.

堆栈区是内存空间,堆栈区是按照先进先出的数据结构,无论是创建还是销毁都是自动为数据分配内存,释放内存,这是系统自动创建的;堆栈区是按照排序的树形数据结构,可以优先取出所需的数据,无论是创建还是销毁都是手动分配内存,释放内存,这是程序员手动编程的。

[En]

Stack area is memory space, stack area is in accordance with the first-in-first-out data structure, whether created or destroyed is automatically allocated memory for data, free memory, which is automatically created by the system; stack area is in accordance with the sorted tree data structure, can give priority to take out the necessary data, whether created or destroyed is manually allocated memory, free memory, which is manually programmed by programmers.

内存空间 特点 内存中的栈区 自动分配,自动释放 内存中的堆区 手动分配,手动释放

当程序在内存中执行时,由于数据类型不同,它将在不同的内存区域中运行。不同的语言有不同的内存分区机制。总的来说,主要有四个方面:

[En]

When the program is executed in memory, it will run in different areas of memory due to different data types. Different languages have different mechanisms for memory partition. Generally speaking, there are four major areas:

  1. 栈区:分配局部变量空间;
  2. 堆区:是用于手动分配程序员申请的内存空间;
  3. 静态区:又称之为全局栈区,分配静态变量,全局变量空间;
  4. 代码区:又称之为只读区、常量区,分配常量和程序代码空间;

上面的堆栈区、读取区、静态区和代码区都只是内存中的一块空间。

[En]

The stack area, read area, static area, and code area above are all just a piece of space in memory.

死递归

所以当我们使用递归函数时,我们应该注意到,递归函数调用的过程是一个打开和释放堆栈的过程,调用时打开堆栈空间,最后释放堆栈空间,所以,如果打开的空间不结束,它将始终存在,并将始终占用内存空间,但堆栈空间是高级空间,如果新打开的空间不释放。之前的空间不会被释放,所以如果我们打开了很多空间,但是不能释放,那么我们脆弱的内存有足够的空间容纳这么多的堆栈吗?如果没有空间,那么我们的计算机就会爆炸,所以我们在使用递归时应该小心避免这种情况。尤其是死递归。

[En]

So when we use recursive functions, we should note that the process of recursive function calls is a process of opening and releasing stacks, opening up stack space when calling, and releasing stack space at the end, so, if the open space does not end, it will always exist and will always occupy memory space, but the stack space is an advanced space, if the newly opened space is not released. The previous space will not be released, so if we open up a lot of space, but can not release it, then does our weak memory have enough space to accommodate so many stacks? If there is no room, then our computer will explode, so we should be careful to avoid this situation when using recursion. Especially dead recursion.

每次调用函数时,都会在内存族中创建一个单独的空间来与该函数协作。这个空间称为堆栈帧空间。

[En]

Each time a function is called, a separate space is created in the memory family to cooperate with the function. This space is called stack frame space.

1、递归是一去一回的过程,调用函数时,会开辟栈帧空间,函数执行结束之后,会释放栈帧空间,递归实际上就是不停地开辟和释放栈帧空间的过程,每次开辟栈帧空间,都是独立的一份,其中的资源不共享。

2、触发回的过程当最后一层栈帧空间全部执行结束的时候,会触底反弹,回到上一层空间的调用处,遇到return,会触底反弹,回到上一层的调用处

3、写递归时,必须给予递归跳出的条件,否则会发生内存溢出,可能会出现死机的情况,所以当递归的层数过多的时候,不建议使用递归。

Python中的环境递归的层数默认为1000层左右,一般都是996层。

下面的递归函数没有跳出递归条件,所以它是一个死递归,执行看看它是否在1000左右。<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>The following recursive function does not jump out of the recursive condition, so it is a dead recursion, execution to see if it is about 1000.</font>*</details>
def recursion(num):
    print(num)
    recursion(num+1)

recursion(1)

尾递归

简单的来说,在函数返回的时候,调用其本身,并且return语句不包含表达式,这样的一个递归函数就是一个尾递归函数。

换句话说,返回的是函数本身是尾递归函数,递归函数只是调用自己。

[En]

In other words, what is returned is that the function itself is a tail recursive function, and the recursive function simply calls itself.

一般情况下,尾递归在参数中计算。

[En]

In general, the tail recursion is calculated in the parameters.

我们开始的例子是尾递归函数吗?不是,因为在该示例中,这是对您所在省份的调用,但不会返回,因此它仍然是一个普通的递归函数。

[En]

Is the example we started with a tail recursive function? No, because in that example, this is a call to your own province, but it is not returned, so it is still an ordinary recursive function.

使用递归的时候,我们通常在一些技术博客上看到一些关于尾递归优化的东西,这是因为尾递归无论调用多少次函数,都只会占用一份空间,只开辟一个栈帧空间,但是目前 cpython 不支持,然而最常见的解释器就是 cpython 。

Python常见的解释器:cpython、pypy、jpython。

与普通递归相比,尾递归的优点是返回值不需要太多额外的操作。

[En]

The advantage of tail recursion over ordinary recursion is that the returned value does not require too much extra operation.

实例

阶乘计算

正整数的阶乘是小于或等于该数的所有正整数的乘积,而0的阶乘是1。

[En]

The factorial of a positive integer is the product of all positive integers less than or equal to that number, and the factorial of 0 is 1.

""" 循环计算 """
def factorial(num):
   if num == 0:
      return 1
   elif num < -1:
      return '只能是零和正整数'
   count = 1
   for i in range(1, num+1):
      count *= i
   return count

res = factorial(5)
print(res)  # 120

""" 使用普通递归 """
def factorial(num):
   if num == 0:
      return 1
   elif num < -1:
      return '只能是零和正整数'
   elif num == 1:
      return num
   return num * factorial(num-1)   # 普通函数返回的是一个表达式

res = factorial(5)
print(res)  # 120

""" 使用尾递归 """
def factorial(num, count=1):
   if num == 0:
      return 1
   elif num < -1:
      return '只能是零和正整数'
   elif num == 1:
      return count
   return factorial(num-1, count*num)   # 尾递归返回的是一个函数,计算式在参数中运算

res = factorial(5)
print(res)  # 120

斐波那契数列

斐波那契数列是以0、1两个数开头,从这个数列从第3个数开始,每一个数都等于前两树之和。

使用循环解决
def fibonacci(num):
   x, y = 0, 1

   if num < 1:
      return '输入大于0的数字'
   elif num == 1:
      return 0
   elif num == 2:
      return 1

   for _ in range(num-2):
      x, y = y, y+x
   return y

res = fibonacci(9)
print(res)  # 21

""" 使用普通递归 """
def fibonacci(num):
   if num < 1:
      return '输入大于0的数字'
   elif num == 1:
      return 0
   elif num == 2:
      return 1

   return fibonacci(num-1) + fibonacci(num-2)

res = fibonacci(9)
print(res)  # 21

""" 使用尾递归 """
def fibonacci(num, x=0, y=1):
   if num < 1:
      return '输入大于0的数字'
   elif num == 1:
      return x
   elif num == 2:
      return y

   return fibonacci(num-1, x=y,  y=(x+y))

res = fibonacci(9)
print(res)  # 21

Original: https://www.cnblogs.com/msr20666/p/16217927.html
Author: 小小垂髫
Title: Python 函数进阶-递归函数

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/499676/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Django测试开发平台搭建

    安装Django把Django放在Python目录下输入python setup.py install 验证是否安装成功输入pythonimport djangodjango.ge…

    Python 2023年8月4日
    068
  • label问题排查:打不开标注好的图像

    问题描述 之前标注好的文件,标注有bbox和若干points。选择Open Dir打开图像目录,选择Change Output Dir选择json文件所在目录。发现有些图片能正常显…

    Python 2023年6月12日
    0143
  • 【学习笔记】 load_dataframe()的学习

    【学习笔记】 load_dataframe()的学习 1 引言最近刚开始尝试复现github上的论文,经过一周环境的配置和调试代码跑起来了,然后学习了相关理论的基础知识,现在开始逐…

    Python 2023年8月21日
    050
  • Python类的封装教程

    封装的本身意思其实就和闭包函数一样,就是把一个函数和变量全都包在一起,但其实这样的说法不是很具体,就是一种很片面的解释 封装数据的主要原因是:保护隐私 封装方法的主要原因是:隔离复…

    Python 2023年10月30日
    026
  • PythonNumpy包的学习和使用

    Numpy包简单介绍 Numpy 是Python中用于科学计算的基础包,广泛应用于数据分析和挖掘numpy的核心基础是N维数组,使用numpy首先需要安装numpy包,在pycha…

    Python 2023年8月25日
    051
  • Go 互斥锁Mutex

    Mutex是一个互斥锁,可以创建为其他结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。互斥锁的作用是保证共享资源同一时刻只能被一个 Goro…

    Python 2023年10月18日
    036
  • 版本控制器Git的使用。

    1、基本介绍 ▶ 版本控制工具 1、集中式版本控制工具 集中式版本控制工具,版本库是集中存放在中央服务器的, team 里每个人 work 时从中央服务器下载代码,是必须联网才能工…

    Python 2023年9月16日
    054
  • Django——django上传文件至腾讯云、阿里云

    文章目录 一、准备工作 二、使用 * 腾讯云配置文件总览 1.初始化 2. 获取客户端对象 3.接口的使用 4.其他部分的操作 三、测试 一、准备工作 首先大家要购买一个腾讯云或者…

    Python 2023年8月4日
    075
  • python实现文件快传不需要服务器,多线程flask+tkinter+requests+threading

    一,程序设计思路 文件快传是指一个设备将文件快速传至另一个设备,而这往往需要中间有个服务器做中转,但这也会影响传输速度,其实我们可以不用这个中转站 当我们需要向其他设备传文件时 我…

    Python 2023年8月11日
    054
  • python dataframe 数据筛选/查询 小案例

    文章目录 一、导入库 二、构建数据集 dataframe 三、小案例 * 3.1 filter + isin 3.2 map 3.3 map + 自定义函数 3.4 apply 3…

    Python 2023年8月7日
    0108
  • 字符串类型

    字符串类型是编程语言里非常重要的数据类型,因为几乎所有的程序主要做的事情就是处理字符串,这个随着大家的学习会有深入的体会。 字符串的定义 python中字符串(str)是使用单引号…

    Python 2023年11月1日
    030
  • pandas数据的合并concat()和merge()

    import pandas as pd 轴向连接(concatenation): pd.concat() 可以沿一个轴将多个DataFrame对象连接在一起, 形成一个新的Data…

    Python 2023年8月8日
    037
  • 如何使用PyCharm快速创建一个Flask项目

    创建一个新的Flask项目 File – New Project选择Flask 之后在创建的文件夹里有自动包含以下三个文件: 其中app.py的默认格式如下: from…

    Python 2023年8月9日
    050
  • 自动化测试框架Pytest(九)——任务管理

    前面几章我们学了一个自动化用例应该怎么写,今天我们来实现一个任务跑多个参数不同的自动化用例。 首先我们在pm_get_token.yaml里新增一个参数parameterize,该…

    Python 2023年9月13日
    043
  • pytest-xdist–分布式执行用例

    pytest-xdist基本的介绍 声明:在介绍pytest-xdist时,本人不讲任何原理,需要看原理的请移至官方:当我们自动化测试用例非常多的时候, 一条条按顺序执行会非常慢,…

    Python 2023年6月3日
    072
  • [Pygame]对话框制作教程.part1

    在大部分游戏中都会有对话框的存在,能推动剧情发展,能让玩家玩懂游戏。 那么在Pygame中,应该怎么制作这种对话框呢? Pygame中基础的文字渲染和绘制: #创建文字库 my_f…

    Python 2023年9月18日
    041
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球