目录递归核心思想关键示例阶乘斐波那契数列汉诺塔题目/规则思考找基线条件疑问为什么第一步1号一定要去C思考怎么“递”疑问怎么就实现了过一遍手动演绎递归过程n 3时递归核心递归函数自己调用自己两个必备条件缺一不可否则无限栈溢出基线条件终止条件满足条件直接返回不再递归调用防止死递归。递归条件把原问题拆解成规模更小、结构相同的子问题。大事化小直到最小可直接求解的情况再逐层返回合并结果。思想关键①不要试图一层一层跟踪全部调用我认为最关键的一条就是不要去质疑自己写的递归或许莫名其妙地就写对了误区手动去模拟每一层递归的执行栈深一大就混乱。正确思维相信递归函数是正确的数学归纳法思想。假设f(n-1)能正确完成任务我只要写好f(n)和f(n-1)的关系即可。汉诺塔相信 hanoi (n-1, ...) 可以把 n-1 个盘子完整挪好不用关心它内部怎么挪。② 递归分为两个阶段递、归递向下不断拆分问题函数不断调用自身压入栈直到碰到基线条件。此时还没有返回结果。归向上回溯到达基线开始返回子问题算出结果逐层向上合并得到大问题答案。阶乘递fact (4)→fact (3)→fact (2)→fact (1)归1→2→6→24③ 递归的本质利用函数调用栈保存中间状态每一次递归调用都会产生独立的局部变量保存在栈帧里。 回溯的时候自动恢复上一层函数的上下文。汉诺塔打印移动步骤就是回溯 / 递过程中输出状态。示例阶乘公式#include stdio.h using namespace std; int fact(int n) { if (n 1 || n 0) // 基线条件 return 1; return n * fact(n - 1); // 递归拆成更小子问题 } int main() { cout fact(4); return 0; }调用过程fact(4)fact(4)4*fact(3)→fact(3)3*fact(2)→fact(2)2*fact(1)→fact(1)1然后回溯2*12→3*26→4*624斐波那契数列公式#include stdio.h #include iostream using namespace std; int fib(int n) { if (n 1 || n 2) return 1; return fib(n - 1) fib(n - 2); } int main() { cout fib(4); return 0; }缺点大量重复计算效率低。汉诺塔今天尝试了在知道要用递归的前提下试着写了汉诺塔结果莫名其妙地写对了。很开心。之后又花了一小下午弄懂其中的原理。题目/规则起始有3 根柱子一般命名A源柱、B辅助柱、C目标柱有n 个大小互不相同的圆盘一开始全部叠在 A 柱大盘在下小盘在上依次堆叠。移动规则一次只能移动 1 个圆盘圆盘只能从一根柱子顶部拿放到另一根柱子顶部任何时刻不能把大盘放在小盘上面目标把全部 n 个圆盘从 A 柱完整移动到 C 柱移动过程遵守上面规则。思考普通的线性运算很难实现用递归最好写以三个n 3为例找基线条件首先想基线条件当n 1时将1号盘从当前柱移动到目标柱并且返回完成“归”。注意这里我没有说从A柱移动到C柱。因为在递归中你无法确定1号盘当前在哪个柱子也不能确定1号盘去哪个柱子。疑问为什么第一步1号一定要去C或许你会问只有一个盘的时候肯定要A - C那多个盘的时候1号盘不能现A - B结论是确实可以但不是最优解了。可以这么理解如果一个柱子的顶端是1号盘。那这个柱子就”死了“——此时这个柱子不能再移入任何的盘子若一开始就将1号盘移动到B柱2号会去C想要再操作只能进行1号盘B - C但这样已经gameover了——两个最小的在C柱上已经不可能实现最短路径了。思考怎么“递”现在不以三个为例了个数太少容易使人想走”捷径“假如现在有八个盘先写个函数模板void hanruo(int n, char ori, char buf, char dest)n为个数ori为柱当前所在的,buf为当前的缓存柱子dest是当前目标移动的柱。注意以上的参数只是针对当前状态这对理解特别重要——因为递归中谁做缓冲柱谁做目标柱都不一定当然第一层的ori buf dest就分别是A B C看最外层当n 8输入进函数后在写入基线条件后要思考面对这个八层的塔要干什么我们想要把1~7层全部挪到B柱来解放8号盘——将其移动到C这是将8号盘移动到C的唯一方式所以也其他没异议于是就开始递归void hanruo(int n, char ori, char buf, char dest) {//ori - A buf - B dest - dest if (n 1) { printf(%d号盘从%c移动到%c\n, n, ori, dest); return; } hanruo(n - 1, ori, dest, buf);hanruo(n - 1, ori, dest, buf);这一句,就表示将n - 1,也就是前七层从oriA以destC为缓冲移动到bufB也就实现了我们想要的效果疑问怎么就实现了这也没写啥具体的代码怎么就实现这个功能了确实我们代码还没写全逻辑还没闭环不了解也没事接着看就好了。之后就要将8号盘移动到Cvoid hanruo(int n, char ori, char buf, char dest) { if (n 1) { printf(%d号盘从%c移动到%c\n, n, ori, dest); return; } hanruo(n - 1, ori, dest, buf); printf(%d号盘从%c移动到%c\n, n, ori, dest);对就加了一句话printf(%d号盘从%c移动到%c\n, n, ori, dest);足以表示这个过程那之后呢这C柱也被“占领了”咋办其实C柱没有”被占“——C柱有最大号的盘子意味着这个柱可以执行任何操作——不会受到阻碍那我们就直接把C柱子看成空的就好了。那是不是和这个情况很像只不过此时满的应该是B 而不是A那不就是初始n 7的样子吗只是缓存柱子不一样了那就可以写void hanruo(int n, char ori, char buf, char dest) { if (n 1) { printf(%d号盘从%c移动到%c\n, n, ori, dest); return; } hanruo(n - 1, ori, dest, buf); printf(%d号盘从%c移动到%c\n, n, ori, dest); hanruo(n - 1, buf, ori, dest); }以oriA为缓冲柱将盘子从bufB移动到destC好了已经写完了下面就交给递归吧。或许你很惊讶——这么短好吧其实我一开始也很惊讶——我压根没打算这点代码可以跑起来但结果确实是对的我很开心#include stdio.h #include iostream using namespace std; void hanruo(int n, char ori, char buf, char dest) { if (n 1) { printf(%d号盘从%c移动到%c\n, n, ori, dest); return; } hanruo(n - 1, ori, dest, buf); printf(%d号盘从%c移动到%c\n, n, ori, dest); hanruo(n - 1, buf, ori, dest); } int main() { int n; scanf(%d,n); hanruo(n, A, B, C); }过一遍再想一遍一套流程中都干了什么第 1 步hanruo(n - 1, ori, dest, buf);把 ori 上面的n-1 个小盘借助 dest搬到 buf。重点 现在要移动的是 n-1 个盘子所以三个柱子角色发生切换起点依旧是ori辅助柱变成了dest目标柱变成了buf效果执行完这一步之后最大的第 n 号盘子孤零零留在 ori 上上面 n-1 个小盘全部挪到 buf。 此时 ori 只剩最大盘下面是空的可以移动大盘。第 2 步printf(%d号盘从%c移动到%c\n, n, ori, dest);移动第 n 号最大盘子从 ori → dest。这一步是当前层真正做的操作递归调用只是安排小盘。 大盘没有任何盘子压着目标柱 dest 现在是空或者上面盘子都比 n 号大满足规则直接移动。执行完最大盘子已经就位固定在 dest 底部之后再也不动它。第 3 步hanruo(n - 1, buf, ori, dest);把 buf 上存放的n-1 个小盘借助 ori搬到 dest。角色再次切换起点现在是bufn-1 个小盘现在在这里辅助柱变成ori现在只有那个已经移走大盘的空柱子目标柱是dest最大盘已经放在这里小盘最后叠上去效果n-1 个小盘全部移动到 dest叠在第 n 号大盘上面。 至此n 个盘子全部从 ori 移到 dest任务完成。对的这已经是一套完美的逻辑所以可以运行起来。手动演绎递归过程虽然我说得头头是道但我实际上了对这个递归的实际操作不很熟悉。所以我决定拿几个比较小的数来演绎一下过程不过一开始写的时候千万不要自己演绎容易把自己绕进去。要靠逻辑与“感觉”。n 3时接着开始递归↓再“归”↓↓↓此时1 2的进程都关闭了再继续3的进程↓这就演示完了虽然我的图可能不是很美观没办法太难画了。通过这个流程希望可以加深你的理解。
企业数字化 ERP 产品动态
相关推荐
Linux中动静态库的理解 软硬链接硬链接ln a b,就是将目标文件a硬链接到文件bls -i 查看文件的inode,ls -li查看所有文件的inode原理Linux 文件由inode 数据块组成:inode:记录文件元信息(权限、大小、指向数据块指针),文件名只是 … · 2026/9/26 12:28:36
MySQL 8.4 MGR组复制三节点单主高可用搭建实战与排错 如果你和我一样,手上的 MySQL 刚好是 8.4.7,又被要求尽快把主从高可用搭起来,那组复制(MySQL Group Replication,简称 MGR)基本是绕不开的选项。这篇文章是我从零开始搭三节点单主 MGR 的完整记录ÿ… · 2026/9/26 12:28:30
JS实现网页自动刷新:定时器、状态保持与条件触发全解析 1. 项目核心思路与方案选型先说结论:网页自动刷新这件事,听起来简单,真正落地的时候会撞上一堆细节问题——刷新后脚本状态丢失、无限循环把页面卡死、目标网站反爬把你封掉等等。我最初接到这个需求是在给一个数据大屏项目做巡检,… · 2026/9/26 13:04:51
Anima+云渲染:建筑动画角色制作与实时渲染全流程指南 做建筑动画或者产品表现的朋友,多半被角色动画这一环节卡过壳。不是模型不会建,也不是渲染参数调不明白,而是让画面里的人物“走起来、动起来、有生活气”这件事,过去实在太费劲了。要么买动捕数据,要么手动K帧&#x… · 2026/9/26 13:04:51
SpringBoot+Vue校园足球俱乐部管理系统开发实战:从数据库到部署全记录 做校园类管理系统这几年,SpringBootVue 基本成了标配组合,但真正把一个“校园足球俱乐部管理系统”从零到一完整落地,里头的坑和细节远比框架选型本身多。这套系统说白了就是解决一个实际问题:俱乐部里几十号球员、每周的集训安排… · 2026/9/26 13:04:51
Python爬虫可视化实战:从数据采集到图表展示的完整项目 我在带Python新手的过程中,最常被问到的一句话就是:“基础语法都过了一遍,但真让我独立做点什么,脑子还是一片空白。”如果你正好处在类似阶段,大概率已经学了三四十天的Python,看教程能看懂,跟… · 2026/9/26 13:04:51
2026 企业 AI 办公工具选型指南:从能力评估到场景落地 不少企业在启动AI办公工具调研时,第一反应是找全网流传的功能对比清单,把不同产品的功能点逐一打勾,谁家覆盖的条目更多就倾向选谁家,也有部分团队直接把采购预算作为第一判断标准,优先挑报价最低的选项,还… · 2026/9/26 13:04:51
Python Flask+Vue企业CRM客户关系管理系统设计与实现解析 项目标题: "python基于flask 企业crm客户关系管理系统的设计与实现-vue pycharm django"关键词: python, flask, crm, vue, django摘要描述: 基于Python Flask与Vue前后端分离架构的企业CRM客户关系管理系统,覆盖数据库设计、JWT鉴权、数据权限隔离、接口… · 2026/9/26 13:04:44
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46