【C语言系列】函数递归
一、递归是什么递归其实是一种解决问题的方法在C语言中递归就是函数自己调用自己。 下面我们看最简单的递归代码代码语言cAI代码解释#include stdio.h int main() { printf(hehe\n); main(); return 0; }运行后提示报错这里的代码会导致栈溢出虽然是个错误的代码但是能够很明确的表达出递归的意思在这里我们可以看出这个代码一直在执行打印操作体现了函数递归的现象但是由于死循环的打印导致了栈溢出的现象。递归的思想把⼀个大型复杂问题层层转化为⼀个与原问题相似但规模较小的子问题来求解直到子问题不能再被拆分递归就结束了。即就是把大事化小的过程。递归中的递就是递推的意思归就是回归的意思。1.1尾递归尾递归是指一个递归函数在调用自身时该递归调用是函数的最后一条语句。换句话说函数在调用自身之后不再执行任何操作而是直接返回递归调用的结果。这种特殊形式的递归称为尾递归。二、递归的限制条件递归在书写的时候有2个必要条件 ①递归存在限制条件当满足这个限制条件的时候递归便不再继续。 ②每次递归调用之后越来越接近这个限制条件。 在下面的例子中我们逐步体会这2个限制条件三、递归举例3.1举例一求n的阶乘⼀个正整数的阶乘factorial是所有小于及等于该数的正整数的积并且0的阶乘为1。 自然数n的阶乘写作n!。题目计算n的阶乘不考虑溢出n的阶乘就是1~n的数字累积相乘。分析和实现示例 我们知道n的阶乘的公式 n n ∗ (n − 1)! 举例说明 5 1 * 2 * 3 * 4 * 5 4 1 * 2 * 3 * 4即 5就等4* 5。 当 n0 的时候n的阶乘是1其余n的阶乘都是可以通过公式计算。如图所示实现代码如下代码语言cAI代码解释#include stdio.h int Fact(int n) { if(n0) return 1; else return n*Fact(n-1); } int main() { int n 0; scanf(%d, n); int ret Fact(n); printf(%d\n, ret); return 0; }运行结果当然这里不考虑n太大的情况n太大存在栈溢出的现象如图下面我们画图推演3.2举例二顺序打印一个整数的每一位题目输入⼀个整数m按照顺序打印整数的每⼀位。 比如 输入1234 输出1 2 3 4 输入520 输出5 2 0分析和实现示例 怎么得到这个数的每⼀位呢 如果n是⼀位数n的每⼀位就是n自己。 n是超过1位数的话就得拆分每⼀位1234%10就能得到4然后1234/10得到123这就相当于去掉了4然后继续对123%10就得到了3再除10去掉3以此类推不断的%10 和 /10 操作直到得到1234的每一位。想到这里我们便有了思路 把Print(1234) 打印1234每⼀位拆解为首先Print(123)打印123的每⼀位再打印得到的4。 把Print(123) 打印123每⼀位拆解为首先Print(12)打印12的每⼀位再打印得到的3。 直到Print打印的是⼀位数直接打印就行。代码实现如下代码语言cAI代码解释void Print(int n) { if(n9) { Print(n/10); } printf(%d , n%10); } int main() { int m 0; scanf(%d, m); Print(m); return 0; }运行结果如图画图推演四、递归与迭代递归是⼀种很好的编程技巧但是和很多技巧⼀样也是可能被误用的就像举例1一样看到推导的公式很容易就被写成递归的形式代码语言cAI代码解释int Fact(int n) { if(n0) return 1; else return n*Fact(n-1); }Fact函数是可以产生正确的结果但是在递归函数调用的过程中涉及⼀些运行时的开销。 在C语言中每⼀次函数调用都要需要为本次函数调用在栈区申请⼀块内存空间来保存函数调用期间的各种局部变量的值这块空间被称为运行时堆栈或者函数栈帧。 函数不返回函数对应的栈帧空间就⼀直占用所以如果函数调用中存在递归调用的话每⼀次递归函数调用都会开辟属于自己的栈帧空间直到函数递归不再继续开始回归才逐层释放栈帧空间。所以如果采用函数递归的方式完成代码递归层次太深就会浪费太多的栈帧空间也可能引起栈溢出stackoverflow的问题。所以如果不想使用递归就得想其他的办法通常就是迭代的方式通常就是循环的方式。 比如计算n的阶乘也是可以产生1~n的数字累计乘在⼀起的。代码语言cAI代码解释int Fact(int n) { int i 0; int ret 1; for(i1; in; i) { ret * i; } return ret; }上述代码是能够完成任务并且效率是比递归的方式更好的。4.1举例三求第n个斐波那契数计算第n个斐波那契数是不适合使用递归求解的但是斐波那契 数的问题通过是使用递归的形式描述的如下看到上图我们就会想到用递归的形式去做如下代码代码语言cAI代码解释#include stdio.h int Fib(int n) { if(n2) return 1; else return Fib(n-1)Fib(n-2); } int main() { int n 0; scanf(%d, n); int ret Fib(n); printf(%d\n, ret); return 0; }当我们n输⼊为50的时候需要很⻓时间才能算出结果这个计算所花费的时间是我们很难接受的这也说明递归的写法是非常低效的那是为什么呢其实递归程序会不断的展开在展开的过程中我们很容易就能发现在递归的过程中会有重复计算而且递归层次越深冗余计算就会越多。我们可以一个测试代码语言cAI代码解释#include stdio.h int count 0; int Fib(int n) { if(n 3) count;//统计第3个斐波那契数被计算的次数 if(n2) return 1; else return Fib(n-1)Fib(n-2); } int main() { int n 0; scanf(%d, n); int ret Fib(n); printf(%d\n, ret); printf(\ncount %d\n, count); return 0; }如图所示计算第40个斐波那契数时需要计算 39088169次可想而知这种方法是冗杂的那这种问题就不适合用递归的方式来来解决问题接下来我们使用迭代的方式来解决这个问题。我们知道斐波那契数的前2个数都1然后前2个数相加就是第3个数那么我们从前往后从小到大计算就行了。 代码如下代码语言cAI代码解释int Fib(int n) { int a 1; int b 1; int c 1; while(n2) { c ab; a b; b c; n--; } return c; }迭代的方式去实现这个代码效率就要高出很多了。五、拓展学习青蛙跳台问题问题有一只青蛙一次可以跳1个台阶一次也可以跳2个台阶问如果跳到第n个台阶有多少种跳法 分析与实现问题 这只青蛙第一次条有两种跳法 ①跳一个台阶剩余n-1个台阶 ②跳两个台阶剩余n-2个台阶 不难发现这是一个斐波那契数列即用以下方法代码语言cAI代码解释#define _CRT_SECURE_NO_WARNINGS 1 #includestdio.h int Jump(int n) { if (n 2) return n; else return Jump(n - 1) Jump(n - 2); } int main() { int x 0; scanf(%d, x); int ret Jump(x); printf(func(%d)%d\n, x, ret); return 0; }

相关新闻

告别多线程!从零手写 select 单线程高并发服务器实战

告别多线程!从零手写 select 单线程高并发服务器实战

在传统的网络编程中,为了同时处理多个客户端的请求,我们通常每来一个连接就开辟一个新线程(或进程)。但当并发量激增时,线程的上下文切换会把服务器的 CPU 资源消耗殆尽。 今天,我们将利用 select 的 I/O 多路转接机制,仅用单线程,就能轻松拿捏多个客户端的并发连接。…

2026/7/2 19:38:22 阅读更多 →
单片机电子秤毕业设计资料:基于HX711与STM32的高效开发实践

单片机电子秤毕业设计资料:基于HX711与STM32的高效开发实践

在单片机电子秤的毕业设计项目中,很多同学都会遇到一个共同的难题:项目周期紧张,但开发过程却总是被各种“坑”拖慢进度。传感器读数跳来跳去、标定过程繁琐到让人怀疑人生、代码越写越乱最后自己都看不懂……这些问题不仅消耗时间&#xff0…

2026/5/17 1:03:49 阅读更多 →
AI 辅助开发实战:信息管理与信息系统专业毕业设计选题的智能生成与验证框架

AI 辅助开发实战:信息管理与信息系统专业毕业设计选题的智能生成与验证框架

最近在帮学校信息管理与信息系统专业优化毕业设计选题流程,发现学生们普遍面临几个头疼的问题:选题重复率高、创新性不足,或者想法很美好但技术实现上根本走不通。老师们也反馈,每年审阅大量相似题目,既耗时又难以激发…

2026/5/17 11:12:11 阅读更多 →

最新新闻

Pandas数据读取全攻略:从CSV到数据库实战技巧

Pandas数据读取全攻略:从CSV到数据库实战技巧

1. Pandas数据读取基础认知作为Python数据分析的瑞士军刀,Pandas的数据读取能力是其核心功能之一。我初次接触Pandas时,最让我惊讶的是它能够用一行代码读取各种格式的数据文件。但真正深入使用后才发现,这看似简单的功能背后隐藏着许多值得深…

2026/7/4 2:15:31 阅读更多 →
BGA芯片手工焊接全流程:从植球到对齐的12个关键步骤与避坑点

BGA芯片手工焊接全流程:从植球到对齐的12个关键步骤与避坑点

BGA芯片手工焊接全流程:从植球到对齐的12个关键步骤与避坑点在电子维修和研发领域,BGA封装芯片的手工焊接一直被视为一项高难度操作。这种底部布满锡球的封装形式,虽然带来了更高的引脚密度和更好的散热性能,但也让焊接过程变得&q…

2026/7/4 2:13:30 阅读更多 →
彻底关闭Hyper-V的完整指南与性能优化

彻底关闭Hyper-V的完整指南与性能优化

1. 为什么需要关闭Hyper-V?Hyper-V作为Windows系统内置的虚拟化技术,确实为开发者和管理员提供了便利的虚拟机环境。但实际工作中,我们经常会遇到必须彻底关闭Hyper-V的场景。最常见的就是当你需要运行VMware Workstation或VirtualBox这类第三…

2026/7/4 2:13:30 阅读更多 →
Apache HTTPD命令详解与Web服务器管理实践

Apache HTTPD命令详解与Web服务器管理实践

1. HTTPD命令概述与核心功能httpd是Apache HTTP服务器的核心管理命令,作为Linux系统中最流行的Web服务器软件之一,Apache通过httpd命令实现服务的全生命周期管理。这个看似简单的命令背后,实际上承载着Web服务最基础也最重要的功能——将你的…

2026/7/4 2:13:30 阅读更多 →
我把考研名师刘晓艳“骂“进了 AI:一个开源 Agent Skill 从 0 到 1 的完整记录

我把考研名师刘晓艳“骂“进了 AI:一个开源 Agent Skill 从 0 到 1 的完整记录

📖 目录 一、起因:当 AI 遇到备考焦虑症二、她是谁:为什么是她三、技术架构:心智蒸馏怎么做的四、核心设计:5 大心智模型 4 条启发式五、表达 DNA:怎么让她"像"刘晓艳六、实战演示:…

2026/7/4 2:11:29 阅读更多 →
Linux文件管理与Vim编辑器高效使用指南

Linux文件管理与Vim编辑器高效使用指南

1. 文件管理命令基础操作在Linux系统中,文件管理是最基础也是最重要的技能之一。掌握这些命令能让你高效地组织和管理文件系统。下面我将详细介绍几个最常用的文件管理命令及其实际应用场景。1.1 目录操作命令pwd(Print Working Directory)命…

2026/7/4 2:11:29 阅读更多 →

日新闻

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 发布:关键安全修复版本,多项问题得到解决

Memcached 1.6.43 正式发布,这是一个关键的安全修复版本,修复了多个方面的问题,还对部分功能进行了优化。 安全修复亮点 此次发布在安全修复上表现突出。binprot 避免了项目引用计数溢出,mcmc 因安全问题提升了上游版本号&#xf…

2026/7/4 0:04:29 阅读更多 →
终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案

终极指南:使用HMCL启动器跨平台畅玩Minecraft的完整解决方案 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecraft! Lau…

2026/7/4 0:06:29 阅读更多 →
KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

KMX63与PIC18F66K40在嵌入式HMI中的硬件协同与低功耗设计

1. KMX63与PIC18F66K40的硬件协同架构解析KMX63作为一款三轴加速度计和磁力计组合传感器,与PIC18F66K40微控制器的搭配堪称嵌入式HMI开发的黄金组合。这套硬件组合的核心优势在于KMX63提供的高精度运动感知能力与PIC18F66K40强大的信号处理能力形成了完美互补。KMX6…

2026/7/4 0:06:29 阅读更多 →

周新闻

月新闻