当前位置: 首页 > news >正文

[Python学习日记-34] 一篇文章让你弄懂 Python 中牛逼的递归函数

[Python学习日记-34] 一篇文章让你弄懂 Python 中牛逼的递归函数

简介

执行过程

特性

练习

简介

        递归函数是指在函数的定义中调用函数自身的一种方式。在 Python 中,任何函数都可以是递归函数。

执行过程

        在这里我们需要求100不断除以2直到商为0为止,打印每次除的商,我们分别用循环和递归来实现这一需求下面我们先来看用循环如何实现,代码如下

n = 100
while n > 0:print(n)n = int(n/2)

代码输出如下:

         那如果用函数应该如何实现呢?我们来看看下面的代码

def calc(n):print(n)n = int(n / 2) # 50if n > 0:calc(n) # 50
calc(100)

代码输出如下:

         从上面的输出效果来看,使用函数递归同样可以实现同样的效果,通俗的来讲其实递归就是自己调用自己的一种方式,从而可以达到循环的效果。是不是这个时候就以为结束了?太年轻了,如果这就是递归的话那样他完全没有必要存在,下面我们加一行代码,你将会看到一个神奇的景象,代码如下

def calc(n):print(n)n = int(n / 2)if n > 0:calc(n)    # n = 50时进入的,现在执行完毕继续执行下面的代码print(n)    # 50
calc(100)

 代码输出如下:

        上面的输出是否震惊了你,这到底是怎么回事!为什么在递归调用自己之后加入这一行代码就会反着输出呢?这里我们就要来说说递归的一个过程了,如下图所示

        如上图所示,函数在每进入下一层的时候,当前层的函数并未结束,它必须等它调用的下一层函数执行结束返回后才能继续往下走。所以最下面的那句 print(n) 会等最里层的函数执行时才会执行,然后不断往外退层,所以会出现0、1、3、6、12、25、50的效果。

特性

  •  必须有一个明确的结束条件

        如果递归函数没有一个明确的结束条件就相当于一个死循环,Python 默认递归1000次就会产生报错,防止内存溢出,报错如下

  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出),栈结构示意图如下

  • 递归函数必须能够组合结果,即每次递归调用都会给出一部分结果,并且所有结果能够合并为最终结果

        递归在特定场景下还是挺有用的,在后面的一些算法就得用到递归,比如堆排、快排等,现在看还是有些复杂的,想要实现这些算法要先完全了解递归的执行过程先。

练习

一、题目

        用递归实现二分查找的算法,以从列表 a=[1,3,4,6,7,8,9,11,15,17,19,21,22,25,29,33,38,69,107] 查找指定的值。

提示:二分法是一种在有序数组中搜索目标元素的算法。它的基本思想是将数组分成两部分,然后确定目标元素可能存在的那一部分,并继续在该部分中查找,直到找到目标元素或确定目标元素不存在为止。

二、答案 

a = [1,3,4,6,7,8,9,11,15,17,19,21,22,25,29,33,38,69,107]
def binary_search(start,end,n,d_list):"""每次把列表规模折半,查找一个数据最多只需要2的n次方 < len(d_list),是2的多少次方,就是最多查多少次。假如列表长度为200,那最多只需查询8次(2**8次方):param start: 查找的起始位置:param end: 查找的结束位置:param n: 要查找的值:param d_list: 要找的列表:return:"""if start < end: # 查找的范围[start:end]依然大于0个mid = (start + end)//2  # 找到中间位置if d_list[mid] > n:  # 如果中间的这个值比要找的n大,代表要往d_list[mid]左边找print("go left",start,mid,end,"--",d_list[start],d_list[mid],d_list[end-1])binary_search(start,mid,n,d_list)elif d_list[mid] < n :  # 要往右边找,继续折半print("go right..",start,mid,end,"--",d_list[start],d_list[mid],d_list[end-1])binary_search(mid+1,end,n,d_list)else:  # 找到了print("find:",d_list[mid],mid)else:  # 假设start=9,end=9, 那d_list[9:9]已经取不到值了,在这种情况下,只能说明,要找的这个值不在这个列表里print("cannot find %s in this data list" % n)
binary_search(0, len(a), 6, a)

 代码输出如下:

相关文章:

  • 【前端安全】js逆向之微信公众号登录密码
  • Golang | Leetcode Golang题解之第440题字典序的第K小数字
  • java-快速将普通main类变为javafx类,并加载自定义fxml
  • go 安装三方库
  • Unity开发绘画板——01.前言
  • C++之String类(下)
  • TypeScript 算法手册【插入排序】
  • 五、CAN总线
  • 《NoSQL》非关系型数据库MongoDB 学习笔记!
  • 2024年3分钟手把手教你激活Guitar Pro 8破解版
  • 工业现场干扰问题及处理方法
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——15.红黑树
  • Eclipse 快捷键:提高开发效率的利器
  • 【C语言】指针详解(一)
  • 在 Kali Linux 中安装 Impacket
  • Google 是如何开发 Web 框架的
  • Angular数据绑定机制
  • isset在php5.6-和php7.0+的一些差异
  • Java IO学习笔记一
  • JavaScript 一些 DOM 的知识点
  • Java比较器对数组,集合排序
  • Js基础知识(一) - 变量
  • Leetcode 27 Remove Element
  • leetcode386. Lexicographical Numbers
  • v-if和v-for连用出现的问题
  • 力扣(LeetCode)357
  • 盘点那些不知名却常用的 Git 操作
  • 普通函数和构造函数的区别
  • 十年未变!安全,谁之责?(下)
  • 探索 JS 中的模块化
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 学习笔记:对象,原型和继承(1)
  • Java数据解析之JSON
  • 交换综合实验一
  • 组复制官方翻译九、Group Replication Technical Details
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​flutter 代码混淆
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #07【面试问题整理】嵌入式软件工程师
  • #if #elif #endif
  • #QT(TCP网络编程-服务端)
  • #vue3 实现前端下载excel文件模板功能
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (正则)提取页面里的img标签
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .CSS-hover 的解释
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?