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

10_函数递归_从阶乘到递归调用栈

函数递归从阶乘到递归调用栈一、本篇文章要解决什么问题上一篇学了函数——函数可以调用别的函数。那函数能不能调用自己能这就是递归。递归是 C 语言中非常有特色的一种编程技巧很多数据结构树、图和算法分治、回溯都依赖递归。但对初学者来说递归最大的困难是想不清楚执行过程。这篇文章帮你搞定三件事递归到底是什么——为什么函数可以调用自己而不乱套递归的两个核心条件递归出口什么时候停 递归关系怎么把大问题变小递归调用栈是怎么回事——帮你从底层理解递和归的过程二、先用一个简单例子理解2.1 套娃的故事俄罗斯套娃打开一个娃娃里面还有一个娃娃再打开还有一个……直到最小的那个打不开了。递一层一层打开——把大问题拆成小问题归一层一层合上——小问题解决了大问题自然有答案递归就是自己调用自己但每次调用时参数在变小或向终止条件靠近最终到达一个最小问题可以直接解决不需要再调用自己。2.2 递归和循环的关系递归能做的事循环也能做反之亦然。区别在于表达方式循环告诉计算机怎么做步骤递归告诉计算机问题是什么定义有些场景用递归表达更自然如树形结构遍历有些场景用循环更高效。初学者先要理解递归的思想再根据场景选择。三、核心知识点讲解3.1 递归的两个必要元素任何一个递归函数必须包含两部分递归出口终止条件什么情况下不继续递归直接返回答案递归关系怎么把规模为 n 的问题转化为规模为 n-1或更小的问题没有出口 无限递归 栈溢出程序崩溃。3.2 阶乘——最经典的递归入门阶乘定义n! 1 × 2 × 3 × ... × n。但用递归思想看n! n × (n-1)! 0! 1 ← 递归出口0 的阶乘定义为 1#includestdio.hintfactorial(intn){if(n0)// 非法输入负数没有阶乘{return-1;// 返回 -1 表示错误调用前应先检查 n}if(n0||n1)// 递归出口0! 1, 1! 1{return1;}returnn*factorial(n-1);// 递归关系}intmain(void){printf(5! %d\n,factorial(5));printf(0! %d\n,factorial(0));// printf(-3! %d\n, factorial(-3)); // 建议在调用前检查不传入负数return0;}运行结果5! 120 0! 1图10-1 阶乘递归展开图图解 factorial(5) 的完整递进和回溯过程。图10-2 递归调用栈示意图从内存角度解释递归的栈本质和栈溢出的风险。3.3 递归调用栈——递和归的详细过程以factorial(5)为例递一层层进入 factorial(5) → 5 * factorial(4) → 4 * factorial(3) → 3 * factorial(2) → 2 * factorial(1) → return 1 ← 到达出口 归一层层返回 ← return 1 ← return 2 * 1 2 ← return 3 * 2 6 ← return 4 * 6 24 ← return 5 * 24 120每次调用factorial都会在调用栈上创建一个新的栈帧保存该层调用的局部变量这里是n和返回位置。当到达出口后栈帧逐个销毁返回值逐层传回。如果递归太深比如factorial(100000)栈空间不够用就发生栈溢出Stack Overflow。3.4 斐波那契数列——递归的双分支斐波那契F(1) 1, F(2) 1, F(n) F(n-1) F(n-2)#includestdio.hintfibonacci(intn){if(n1||n2)// 递归出口两个终止条件{return1;}returnfibonacci(n-1)fibonacci(n-2);// 两个递归调用}intmain(void){for(inti1;i10;i){printf(%d ,fibonacci(i));}printf(\n);return0;}运行结果1 1 2 3 5 8 13 21 34 55效率问题fibonacci(5)会调用fibonacci(4)和fibonacci(3)而fibonacci(4)又会调用fibonacci(3)——重复计算了大量子问题。这是斐波那契递归实现的最大缺点也是为什么面试里常被问到优化方案。图10-3 斐波那契递归重复计算图直观展示为什么斐波那契递归效率低。四、完整代码示例一个递归思想的实用案例——递归打印一个整数按位拆分的结果#includestdio.h// 递归打印整数的每一位voidprintDigits(intn){if(n10)// 递归出口只剩一位{printf(%d ,n);return;}printDigits(n/10);// 先递归打印高位printf(%d ,n%10);// 再打印当前最低位}// 循环版本用于对比voidprintDigitsLoop(intn){// 先处理逆序问题把每一位存到数组再倒序输出intdigits[10];intcount0;while(n0){digits[count]n%10;n/10;}for(inticount-1;i0;i--){printf(%d ,digits[i]);}}intmain(void){intnum12345;printf(数字%d\n,num);printf(递归打印);printDigits(num);printf(\n);printf(循环打印);printDigitsLoop(num);printf(\n);// 演示 10 以内数字直接触发出口printf(\n数字 7 递归打印);printDigits(7);printf(\n);// 注意当前 printDigits 主要面向正整数。输入 0 会输出 0因 n10 成立// 输入负数则 n%10 的结果与具体实现有关建议调用前检查参数。return0;}五、运行结果数字12345 递归打印1 2 3 4 5 循环打印1 2 3 4 5 数字 7 递归打印7六、代码逐行解析递归打印的核心逻辑voidprintDigits(intn){if(n10)// 递归出口{printf(%d ,n);return;}printDigits(n/10);// 先递归处理高位printf(%d ,n%10);// 再打印当前最低位}执行过程以 n123 为例printDigits(123) → if (123 10) 不成立 → printDigits(12) ← 递先处理高位 → if (12 10) 不成立 → printDigits(1) ← 再递只剩最高位 → if (1 10) 成立 → printf(1) → return → printf(2) ← 归打印当前位 → printf(3) ← 归打印当前位关键点printDigits(n/10)调用之后的代码在归阶段才执行。这就是递归的顺序控制能力——先处理深层问题再回溯处理本层问题。用循环实现这个效果需要额外用数组倒序代码远不如递归简洁。七、初学者常见错误错误1缺少递归出口——无限递归// 错误写法——没有出口intfactorial(intn){returnn*factorial(n-1);// n 越来越小但永远不会停}// 结果栈溢出Stack Overflow程序崩溃错误2递归出口的条件覆盖面不够// 错误写法——n1 有出口n0 会无限递归intfactorial(intn){if(n1)return1;returnn*factorial(n-1);}// factorial(0) → factorial(-1) → ... 无限递归// 正确if (n 1) return 1;错误3递归参数没有向出口靠近// 错误写法——参数不变永远到不了出口voidbadRecursion(intn){if(n0)return;badRecursion(n);// 应该传 n-1}错误4大规模斐波那契递归卡死printf(%d\n,fibonacci(50));// 极慢计算量指数级增长// 要么用循环实现要么用记忆化缓存中间结果错误5在递归函数里用 static 变量累积结果// 这种写法虽然可能通过但破坏了递归的纯粹性第二次调用就有残留值intfactorial(intn){staticintresult1;// 不推荐}八、练习题练习题1递归求和用递归实现一个函数int sum(int n)返回 12…n 的值。在 main 中测试sum(100)。提示递归关系sum(n) n sum(n-1)出口sum(1) 1。练习题2递归反转字符串用递归实现一个函数将用户输入的字符串反转输出只输出不修改原数组。提示先输出最后一个字符再递归处理前面的子串。出口字符串长度为 0 或 1。练习题3汉诺塔问题选做阅读汉诺塔问题的描述用递归输出将 n 个盘子从 A 柱移到 C 柱的步骤每次只能移一个盘子且大盘不能放在小盘上面。这是递归思想的经典问题n3 时应有 7 步。九、本篇总结递归 函数调用自己必须包含递归出口和递归关系两个要素缺少出口 无限递归 栈溢出这是递归最严重的错误递是压栈过程问题缩小归是出栈过程答案合并斐波那契递归实现效率低——重复计算太多用循环或记忆化优化递归和循环可以互相转换选择让代码更清晰的写法图10-4 递归打印数字的递/归过程图帮助理解递归调用之后的代码在归阶段执行这一核心概念。

相关文章:

10_函数递归_从阶乘到递归调用栈

函数递归:从阶乘到递归调用栈 一、本篇文章要解决什么问题 上一篇学了函数——函数可以调用别的函数。那函数能不能调用自己?能,这就是递归。 递归是 C 语言中非常有特色的一种编程技巧,很多数据结构(树、图&#xff0…...

进程与线程:并发编程基础

摘要:进程与线程是操作系统面试的必考点,也是理解 AI 分布式训练和多线程数据加载的基础。本文从进程内存模型出发,系统讲解线程同步机制(锁、信号量、条件变量),并通过 Python 代码展示多线程爬虫和生产者…...

大数据+大模型=乘法效应?6个场景告诉你,大模型如何让你的数据平台“活”起来!

本文探讨了大数据与大模型的关系,提出大模型是大数据平台的“发动机”。文章重点介绍了六个必须使用大模型才能解放双手的场景,包括数据血缘解析、Text2SQL、数据质量智能巡检、调度任务智能运维、元数据管理和报告自动生成。这些场景展示了大模型如何通…...

计算机网络基础:TCP/IP 与 HTTP 核心知识

摘要:计算机网络是后台开发和 AI 基础设施面试的重要考点。本文从 OSI 七层模型出发,重点讲解 TCP 三次握手/四次挥手、HTTP/HTTPS 协议、以及 WebSocket 和 RESTful API 设计,并结合 Python 代码展示 Socket 编程和简单的 HTTP 服务器实现。…...

缓存设计:从 LRU 到 Redis 实战

摘要:缓存是提升系统性能的第一道防线,也是面试中系统设计环节的核心话题。本文系统讲解缓存的四大置换策略、LRU 和 LFU 的实现原理,并结合 Python 代码展示完整的缓存系统。AI 开发者还将学到 KV Cache 在 LLM 推理中的关键作用。一、为什么…...

14000华夏之光永存:开源:华为五大全栈硬核技术揭榜课题完整梳理(预刊抽取篇)

开源:华为五大全栈硬核技术揭榜课题完整梳理(预刊抽取篇) 摘要 本文完整收录黄大年茶思屋珠峰会战第八期5项前沿技术揭榜难题,原样保留技术背景、技术挑战、现有方案、现存缺陷与量化技术诉求,不做内容删减与篡改。本文…...

深度强化学习与控制2026 课程总结Week2

深度Q网络——DQN算法流程: (1) 初始化网络参数 (2) 初始化网络参数 (3) 初始化经验回放池R (4) 进入循环迭代训练:for 序列 do获取初始状态for 时间步 do 根据以贪婪策略选择动作,获得,存入经验回放池R若R中数据充足,从R中采样…...

2026年腾讯云OpenClaw/Hermes Agent配置Token Plan怎么安装看这

2026年腾讯云OpenClaw/Hermes Agent配置Token Plan怎么安装看这。OpenClaw是开源的个人AI助手,Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流 AI 工具&…...

2026年阿里云OpenClaw/Hermes Agent配置Token Plan怎么安装看这

2026年阿里云OpenClaw/Hermes Agent配置Token Plan怎么安装看这。OpenClaw是开源的个人AI助手,Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流 AI 工具&…...

TVA驱动智能家居的视觉范式革命(11)

重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...

项目介绍 基于Python的大学生竞赛组队系统设计与实现(含模型描述及部分示例代码)专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢

基于Python的大学生竞赛组队系统设计与实现的详细项目实例 请注意此篇内容只是一个项目介绍 更多详细内容可直接联系博主本人 或者访问对应标题的完整博客或者文档下载页面(含完整的程序,GUI设计和代码详解) 大学生竞赛已成为高校人才培养…...

CANN-ops-nn-昇腾NPU神经网络算子的积木盒子

你去超市买过那种混合装坚果吗?一袋里面核桃、腰果、巴旦木都有,打开直接吃,不用自己搭配。ops-nn 在昇腾CANN生态里就是这个角色——把神经网络最常用的算子打包好了,打开就能用。昇腾NPU跑大模型、跑视觉模型,底层都…...

proj-agones:知识点:helm

helm install之后的log be like:(base) savilahaobogon ~ % helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --create-namespace NAME: prometheus LAST DEPLOYED: Wed May 20 14:54:39 2026 NAMESPACE: monitoring STATUS: de…...

HTML 零基础入门:从概念到常用标签详解,前端入门超详细版

一、HTML介绍HTML 全称超文本标记语言(HyperText Markup Language),是搭建网页的基础骨架语言,也是前端开发最入门、最核心的语言。它不属于编程语言,没有逻辑运算、没有变量,只是一套标记标签,…...

软考中级嵌入式——第九章 数据结构与算法

1.数据结构与算法概念1.1数据结构数据结构概述:数据结构是计算机存储、组织数据的方式。简单来说,就是如何把现实中的数据(如数字、文字、图片)合理地整理好,放进计算机里,并定义好对这些数据可以做什么操作…...

项目介绍 基于java+vue的跨境电商销售预测与可视化平台设计与实现(含模型描述及部分示例代码)专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢

基于javavue的跨境电商销售预测与可视化平台设计与实现的详细项目实例 请注意此篇内容只是一个项目介绍 更多详细内容可直接联系博主本人 或者访问对应标题的完整博客或者文档下载页面(含完整的程序,GUI设计和代码详解) 跨境电商销售预测…...

紧急预警:2024年底起,欧盟CSRD与国内《电力人工智能应用安全规范》将强制要求Agent可解释性审计——3类高危黑箱行为自查清单

更多请点击: https://codechina.net 第一章:AI Agent能源行业应用 AI Agent正以前所未有的深度融入能源行业的核心环节,从智能电网调度、风/光功率预测,到设备故障诊断与碳排优化决策,其自主感知、推理与执行能力显著…...

单一职责原则 登录功能重构笔记

核心定义单一职责原则:一个类只干一件事,只有一个修改的理由,避免功能杂糅、代码耦合。原有问题原始 Login 登录类,把界面展示、数据库连接、数据查询、登录校验、程序启动全部堆在一个类里,职责混乱,任何小…...

数据类型与变量-Part3-输入输出格式化艺术

C语言输入输出格式化艺术系列导航 ✅ Part 1: C语言数据类型与变量(基础篇)✅ Part 2: C语言内存探秘(进阶篇)📍 Part 3: C语言输入输出格式化艺术 ← 你在这里上一篇我们深入了内存底层,这篇我们来聊聊你和…...

【Web安全】-企业资产信息收集(1):信息收集介绍,域名信息收集,主域名查询,ICP备案号查询,备案实体查询,工业和信息化部政务服务平台查询,怎样收集

🦆 个人主页:深邃- ❄️专栏传送门:《C语言》《数据结构与算法》《Web安全》 🌟Gitee仓库:《C语言》《数据结构与算法》 特此声明:本次信息收集均在日期授权时间内收集,并且都将所有人员信息打…...

CNKI-download:3步实现知网文献批量下载与管理的Python自动化工具

CNKI-download:3步实现知网文献批量下载与管理的Python自动化工具 【免费下载链接】CNKI-download :frog: 知网(CNKI)文献下载及文献速览爬虫 (Web Scraper for Extracting Data) 项目地址: https://gitcode.com/gh_mirrors/cn/CNKI-download 你是否曾为手动…...

从零入门 OpenAI Codex|登录、权限、终端、记忆配置全实操

我先来简单介绍一下Codex。 Codex是 OpenAI 推出的 AI 编程模型与工具系列。Codex 最初于 2021 年作为 OpenAI API 的一部分发布,基于 GPT 架构专门针对代码数据进行了训练。2024 至 2025 年间,OpenAI 推出了独立的 Codex CLI命令行工具,使其…...

Kubernetes DaemonSet深度解析:管理集群守护进程的最佳实践

Kubernetes DaemonSet深度解析:管理集群守护进程的最佳实践 一、DaemonSet概述 DaemonSet 是Kubernetes中用于在集群的每个节点上运行一个Pod副本的控制器。它确保所有节点(或满足特定条件的节点)都运行该Pod的一个实例。 1.1 DaemonSet应…...

昇腾CANN runtime Stream 调度引擎:从命令队列到 AI Core 的执行链路

用户看到的是一行 torch.nn.functional.softmax(x)&#xff0c;背后 runtime 要做&#xff1a;分配 Stream、入队命令、调度到 AI Core、等待完成、同步结果。如果这一行的延迟是 10μs&#xff0c;runtime 的调度开销必须 < 0.5μs——否则就是 5% 的性能损失。 runtime 的…...

Kubernetes StatefulSet深度解析:管理有状态应用的最佳实践

Kubernetes StatefulSet深度解析&#xff1a;管理有状态应用的最佳实践 一、StatefulSet概述 StatefulSet 是Kubernetes中用于管理有状态应用的控制器。它为Pod提供稳定的网络标识和持久化存储&#xff0c;确保Pod的有序部署、扩展和更新。 1.1 StatefulSet vs Deployment …...

JDK常用类与工具(速览版)

JDK常用类与工具&#xff08;速览版&#xff09;JDK&#xff08;Java Development Kit&#xff09;提供了丰富的标准库和实用工具&#xff0c;它们构成了Java开发者日常工作的基石。掌握这些核心类、集合框架、并发工具、IO/NIO库、日期时间API、正则表达式、异常处理机制、日志…...

GPS测速仪SpeedView 3.2.0汉化版 精准速度 实时测速工具

一款实时测速应用程序&#xff0c;英文名为“SpeedView”&#xff0c;安装到手机上就能够在开车的时候查看仪表盘车辆的速度是否准确 实时测速&#xff1a;通过GPS精准定位&#xff0c;实时显示当前速度、平均速度和最高速度&#xff0c;支持多种单位切换&#xff08;km/h、mp…...

阿里巴巴运营/2026年阿里巴巴1688店铺效果越来越差的3个核心原因(附解决方案)

阿里巴巴运营/2026年阿里巴巴1688店铺效果越来越差的3个核心原因&#xff08;附解决方案&#xff09;最近很多工厂老板跟我说&#xff0c;小峰老师&#xff0c;我这1688店铺怎么越做越没效果了&#xff1f;明明以前还能来几个询盘&#xff0c;现在越来越少&#xff0c;是不是16…...

CANN-ATB量化推理-昇腾NPU上W8A8量化为什么比W4A16更实用

Llama2-70B 权重 140GB&#xff0c;8 卡 TP 刚好放得下但没什么余量给 KV Cache。W8A8 量化把权重从 fp16 压到 int8&#xff0c;权重体积减半&#xff0c;4 卡就能跑 70B。W4A16 理论上压得更狠&#xff08;4 倍压缩&#xff09;&#xff0c;但精度损失在实际业务里往往不可接…...

CANN-HCCL-昇腾NPU分布式训练的通信库怎么选

8 卡 Atlas 800I A2 内部走 HCCS&#xff08;带宽 200GB/s&#xff09;&#xff0c;跨机走 RoCE&#xff08;带宽 100GB/s&#xff09;。HCCL 是昇腾NPU的通信库&#xff0c;对标 NVIDIA 的 NCCL。Tensor Parallel 和 Pipeline Parallel 的 All-Reduce、All-to-All 都靠它。 HC…...