递归函数详解

定义

递归是指一个函数在其定义中直接或间接地调用自身的方法。通过这种方式,函数可以将一个复杂的问题分解为规模更小的、与原问题相似的子问题,然后通过不断地解决这些子问题来最终解决整个问题。

组成部分

递归主体

这是函数中递归调用自身的部分,它通过将问题分解为更小的子问题来逐步解决整个问题。

递归终止条件

也称为基本情况,是递归函数停止调用自身的条件。当满足这个条件时,函数不再进行递归调用,而是直接返回一个已知的结果。如果没有正确的终止条件,递归函数将无限循环,导致栈溢出等错误。

递归的层层展开和回溯过程

层层展开过程

层层展开指的是递归函数不断调用自身,问题规模逐步缩小,直至达到递归终止条件的过程。

逐步回溯过程

逐步回溯是指递归函数在达到终止条件后,依次返回上一层调用函数,继续执行后续代码的过程。最终回溯到初始调用。

递归函数中多次递归调用

递归函数中多次递归调用是依次进行的,每次调用都会创建新的栈帧压入调用栈,直到遇到递归终止条件后开始逐步返回,栈帧也依次弹出,返回到上一层调用函数中继续执行后续代码。这样就实现了递归的层层展开和逐步回溯的过程。

总结

递归的层层展开过程是不断将原问题分解为规模更小的子问题,直到达到递归终止条件;而逐步回溯过程则是在子问题解决后,依次返回上一层,利用子问题的结果解决更大规模的问题,最终得到原问题的解。整个过程通过调用栈来管理函数的调用和返回顺序,确保程序的正确执行。

生动理解

当你收到一份快递的时候,你打开快递包装,发现还有包装,再打开包装,发现还有包装,再打开包装,......…终于,你收到了一张字条,上面写着“我好饿啊,你干嘛要吃牛排意大利面?cnm”。此时,你感到很惭愧,不该在这么晚发表美食,于是,你写了一张抱歉信,然后你将快递重新包装回去,包装一层,再包装一层,........…,终于你包装完了,将快递按原地址发送回去。

(该解释来自acwing中的房智玄)

举例

以汉诺塔问题的递归函数为例:

void dfs(int n, char x, char y, char z)
{if(n==0) return; // 基本情况:没有盘子需要移动dfs(n-1, x, z, y); // 递归步骤1:将n-1个盘子从x移动到y,使用z作为辅助printf("%c->%d->%c\n", x, n, z); // 打印当前步骤:将第n个盘子从x移动到zdfs(n-1, y, x, z); // 递归步骤2:将n-1个盘子从y移动到z,使用x作为辅助
}

假设我们调用  dfs(3, 'A', 'B', 'C') ,下面详细阐述其层层展开和逐步回溯的过程。

层层展开过程

初始调用

我们调用  dfs(3, 'A', 'B', 'C') ,系统为该函数创建一个栈帧并压入调用栈。栈帧包含参数  n = 3 , x = 'A' , y = 'B' , z = 'C'  以及返回地址等信息。此时函数要解决的问题是把 3 个盘子从柱子  A  借助柱子  B  移动到柱子  C 。

第一次递归展开

在  dfs(3, 'A', 'B', 'C')  中,由于  n != 0 ,执行  dfs(n - 1, x, z, y) ,也就是  dfs(2, 'A', 'C', 'B') 。
 
系统为  dfs(2, 'A', 'C', 'B')  创建新的栈帧并压入调用栈。此时问题变为把 2 个盘子从柱子  A  借助柱子  C  移动到柱子  B 。

第二次递归展开

 在  dfs(2, 'A', 'C', 'B')  中,因为  n != 0 ,执行  dfs(n - 1, x, z, y) ,即  dfs(1, 'A', 'B', 'C') 。
 
系统为  dfs(1, 'A', 'B', 'C')  创建新的栈帧并压入调用栈。现在问题是把 1 个盘子从柱子  A  借助柱子  B  移动到柱子  C 。

第三次递归展开

在  dfs(1, 'A', 'B', 'C')  中,由于  n != 0 ,执行  dfs(n - 1, x, z, y) ,也就是  dfs(0, 'A', 'C', 'B') 。
 
系统为  dfs(0, 'A', 'C', 'B')  创建新的栈帧并压入调用栈。此时问题规模缩小到 0 个盘子的移动。

达到终止条件

在 dfs(0, 'A', 'C', 'B')  中,因为 n == 0 ,满足递归终止条件,函数不再进行递归调用,准备开始回溯。

逐步回溯过程

第一次回溯

dfs(0, 'A', 'C', 'B')  执行  return  语句,其栈帧从调用栈中弹出。
 
程序控制流回到  dfs(1, 'A', 'B', 'C')  中调用  dfs(0, 'A', 'C', 'B')  的下一行代码,即  printf("%c->%d->%c\n", x, n, z); ,输出  A->1->C ,表示将编号为 1 的盘子从柱子  A  移动到柱子  C 。
 
第二次递归调用(在  dfs(1, 'A', 'B', 'C')  中)
 
接着执行  dfs(n - 1, y, x, z) ,即  dfs(0, 'B', 'A', 'C') 。
 
系统为  dfs(0, 'B', 'A', 'C')  创建新的栈帧并压入调用栈。

再次达到终止条件并回溯

在  dfs(0, 'B', 'A', 'C')  中,因为  n == 0 ,执行  return  语句,其栈帧从调用栈中弹出。
 
回到  dfs(1, 'A', 'B', 'C')  中调用  dfs(0, 'B', 'A', 'C')  的下一行代码,此时  dfs(1, 'A', 'B', 'C')  函数执行完毕,其栈帧从调用栈中弹出。

继续回溯到 dfs(2, 'A', 'C', 'B')

 回到  dfs(2, 'A', 'C', 'B')  中调用  dfs(1, 'A', 'B', 'C')  的下一行代码,即  printf("%c->%d->%c\n", x, n, z); ,输出  A->2->B ,表示将编号为 2 的盘子从柱子  A  移动到柱子  B 。
 
接着执行  dfs(n - 1, y, x, z) ,即  dfs(1, 'C', 'A', 'B') ,重复上述递归展开和回溯的过程。

最终回溯到初始调用

 经过多次递归展开和回溯,最终回到  dfs(3, 'A', 'B', 'C')  中调用  dfs(2, 'A', 'C', 'B')  的下一行代码,输出  A->3->C ,表示将编号为 3 的盘子从柱子  A  移动到柱子  C 。
 
再执行  dfs(n - 1, y, x, z) ,完成所有盘子的移动操作, dfs(3, 'A', 'B', 'C')  函数执行完毕,调用栈为空。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79304.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Core Web API 配置系统集成

文章目录 前言一、配置源与默认设置二、使用步骤1)创建项目并添加配置2)配置文件3)强类型配置类4)配置Program.cs5)控制器中使用配置6)配置优先级测试7)动态重载配置测试8)运行结果示…

在生信分析中,从生物学数据库中下载的序列存放在哪里?要不要建立一个小型数据库,或者存放在Gitee上?

李升伟 整理 在Galaxy平台中使用时,从NCBI等生物学数据库下载的DNA序列的存储位置和管理方式需要根据具体的工作流程和需求进行调整。以下是详细的分步说明和建议: 一、Galaxy中DNA序列的默认存储位置 在Galaxy的“历史记录”(History&…

SDK游戏盾如何接入?复杂吗?

接入SDK游戏盾(通常指游戏安全防护类SDK,如防DDoS攻击、防作弊、防外挂等功能)的流程和复杂度取决于具体的服务商(如腾讯云、上海云盾等)以及游戏类型和技术架构。以下是一般性的接入步骤、复杂度评估及注意事项&#…

通过类似数据蒸馏或主动学习采样的方法,更加高效地学习良品数据分布

好的,我们先聚焦第一个突破点: 通过类似数据蒸馏或主动学习采样的方法,更加高效地学习良品数据分布。 这里我提供一个完整的代码示例: ✅ Masked图像重建 残差热力图 这属于自监督蒸馏方法的一个变体: 使用一个 预…

【课题推荐】多速率自适应卡尔曼滤波(MRAKF)用于目标跟踪

多速率自适应卡尔曼滤波(Multi-Rate Adaptive Kalman Filter, MRAKF)是一种针对多传感器异步数据融合的滤波算法,适用于传感器采样率不同、噪声特性时变的目标跟踪场景。本文给出一个多速率自适应卡尔曼滤波框架,以无人机跟踪场景为例,融合IMU和GPS数据 文章目录 背景多速…

软考 系统架构设计师系列知识点之杂项集萃(49)

接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(48) 第76题 某文件管理系统在磁盘上建立了位视图(bitmap),记录磁盘的使用情况。若磁盘上物理块的编号依次为:0、1、2、……&#xff1b…

HTTP:七.HTTP缓存

HTTP缓存介绍 HTTP缓存是一种通过存储网络资源的副本,以减少对原始服务器请求的技术。当客户端再次请求相同资源时,如果该资源未过期,服务器可以直接从本地缓存中提供响应,而无需再次从原始服务器获取。这大大减少了网络延迟,提高了加载速度,并减轻了服务器的负载。HTTP…

WPF 图标原地旋转

如何使元素原地旋转 - WPF .NET Framework | Microsoft Learn <ButtonRenderTransformOrigin"0.5,0.5"HorizontalAlignment"Left">Hello,World<Button.RenderTransform><RotateTransform x:Name"MyAnimatedTransform" Angle"…

NO.91十六届蓝桥杯备战|图论基础-图的存储和遍历|邻接矩阵|vector|链式前向星(C++)

图的基本概念 图的定义 图G是由顶点集V和边集E组成&#xff0c;记为G (V, E)&#xff0c;其中V(G)表⽰图G中顶点的有限⾮空集&#xff1b;E(G)表⽰图G中顶点之间的关系&#xff08;边&#xff09;集合。若 V { v 1 , v 2 , … , v n } V \left\{ v_{1},v_{2},\dots,v_{n} …

【项目日记(一)】-仿mudou库one thread oneloop式并发服务器实现

1、模型框架 客户端处理思想&#xff1a;事件驱动模式 事件驱动处理模式&#xff1a;谁触发了我就去处理谁。 &#xff08; 如何知道触发了&#xff09;技术支撑点&#xff1a;I/O的多路复用 &#xff08;多路转接技术&#xff09; 1、单Reactor单线程&#xff1a;在单个线程…

Go语言实现OAuth 2.0认证服务器

文章目录 1. 项目概述1.1 OAuth2 流程 2. OAuth 2.0 Storage接口解析2.1 基础方法2.2 客户端管理相关方法2.3 授权码相关方法2.4 访问令牌相关方法2.5 刷新令牌相关方法 2.6 方法调用时序2.7 关键注意点3. MySQL存储实现原理3.1 数据库设计3.2 核心实现 4. OAuth 2.0授权码流程…

结合 Python 与 MySQL 构建你的 GenBI Agent_基于 MCP Server

写在前面 商业智能(BI)正在经历一场由大型语言模型(LLM)驱动的深刻变革。传统的 BI 工具通常需要用户学习复杂的界面或查询语言,而生成式商业智能 (Generative BI, GenBI) 则旨在让用户通过自然语言与数据交互,提出问题,并获得由 AI 生成的数据洞察、可视化建议甚至完整…

Linux中常用命令

目录 1. linux目录结构 2. linux基本命令操作 2.1 目录操作命令 2.2 文件操作命令 2.3 查看登录用户命名 2.4 文件内容查看命令 2.5 系统管理类命令 3. bash通配符 4. 压缩与解压缩命令 4.1 压缩和解压缩 4.2 测试网络连通性命令 ping 4.3 vi编辑器 4.4 管道操作(…

C++ 与 MySQL 数据库优化实战:破解性能瓶颈,提升应用效率

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

tcp特点+TCP的状态转换图+time_wait详解

tcp特点TCP的状态转换图time wait详解 目录 一、tcp特点解释 1.1 面向连接 1.1.1 连接建立——三次握手 1.1.2 连接释放——四次挥手 1.2 可靠的 1.2.1 应答确认 1.2.2 超时重传 1.2.3 乱序重排 1.2.4 去重 1.2.5 滑动窗口进行流量控制 1.3 流失服务&#xff08;字节…

探秘 Ruby 与 JavaScript:动态语言的多面风采

1 语法特性对比&#xff1a;简洁与灵活 1.1 Ruby 的语法优雅 Ruby 的语法设计旨在让代码读起来像自然语言一样流畅。它拥有简洁而富有表现力的语法结构&#xff0c;例如代码块、符号等。 以下是一个使用 Ruby 进行数组操作的简单示例&#xff1a; # 定义一个数组 numbers [1…

点评项目回顾

表结构 基于Session实现登录流程 发送验证码&#xff1a; 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行保存&#xf…

OpenShift介绍,跟 Kubernetes ,Docker关系

1. OpenShift 简介 OpenShift是一个开源项目,基于主流的容器技术Docker及容器编排引擎Kubernetes构建。可以基于OpenShift构建属于自己的容器云平台。OpenShift的开源社区版本叫OpenShift Origin,现在叫OKD。 OpenShift 项目主页:https://www.okd.io/。OpenShift GitHub仓库…

Ubuntu服务器性能调优指南:从基础工具到系统稳定性提升

一、性能监控工具的三维应用 1.1 监控矩阵构建 通过组合工具搭建立体监控体系&#xff1a; # 实时进程监控 htop --sort-keyPERCENT_CPU# 存储性能采集 iostat -dx 2# 内存分析组合拳 vmstat -SM 1 | awk NR>2 {print "Active:"$5"MB Swpd:"$3"…

计算机视觉——基于MediaPipe实现人体姿态估计与不良动作检测

概述 正确的身体姿势是个人整体健康的关键。然而&#xff0c;保持正确的身体姿势可能会很困难&#xff0c;因为我们常常会忘记。本博客文章将逐步指导您构建一个解决方案。最近&#xff0c;我们使用 MediaPipe POSE 进行身体姿势检测&#xff0c;效果非常好&#xff01; 一、…