【独家】C语言100篇:从入门到天花板 第17篇
函数嵌套与递归:递归思想与终止条件
作者:华夏之光永存
前言
大家好,我是华夏之光永存,欢迎继续阅读 优快云独家高质量专栏《C语言100篇:从入门到天花板》。
在前面我们学习了函数的定义、调用、参数传递,已经可以完成模块化、结构化的程序编写。而今天要学习的递归(Recursion),是计算机科学中最优雅、最强大、最接近数学思维的编程思想,也是二叉树、快速排序、二分查找、回溯、动态规划等高级算法的核心基础。
本篇将从递归本质、思想拆解、嵌套与递归区别、终止条件、经典案例、栈溢出问题、企业级用法全方位精讲,全文≥2000字,底层逻辑+图文拆解+实战一步到位,严格遵循本源法则:化繁为简、回归本质、逻辑闭环。
掌握递归,你的编程思维将直接进入算法级。
一、递归的本源:什么是递归?为什么它如此强大?
递归的本质只有一句话:
函数自己调用自己。
就像:
- 镜子照镜子
- 俄罗斯套娃
- 故事里有同一个故事
- 数学上的递推公式
递归的核心思想:把大问题,拆解成结构相同但规模更小的子问题,直到小到可以直接得出答案,再一步步返回计算。
递归与循环的区别
- 循环:从底向上,重复执行
- 递归:从上向下,拆解问题,再回溯结果
递归的代码更短、更接近数学公式、逻辑更清晰,特别适合处理非线性、分层、嵌套结构(树、图、目录、嵌套结构)。
二、递归的两个必备条件(缺一不可)
递归不是无限调用,必须满足两个铁律,否则栈溢出崩溃!
1)递归终止条件(出口)
- 问题小到可以直接算出结果
- 不再递归,直接 return
- 没有出口 = 死递归 = 栈溢出 = 程序崩溃
2)递归递推公式(逼近出口)
- 把问题规模缩小
- 向终止条件靠近
- 保证递归能停下来
三、递归执行过程:调用 → 递去 → 归来
递归完整流程分三步:
- 递去:不断调用自己,问题不断变小
- 抵达:到达终止条件,开始返回
- 归来:一层层向上返回结果
先递去,后归来。
四、最简单递归:求阶乘(入门必背)
数学公式:
n! = n * (n-1)!
1! = 1
0! = 1
递归代码:
long long factorial(int n) {
// 1. 终止条件
if (n == 0 || n == 1) {
return 1;
}
// 2. 递推公式:自己调用自己
return n * factorial(n - 1);
}
执行 factorial(3) 过程:
factorial(3)
= 3 * factorial(2)
= 3 * 2 * factorial(1)
= 3 * 2 * 1
= 6
五、递归经典案例1:斐波那契数列
公式:
f(1)=1, f(2)=1
f(n)=f(n-1)+f(n-2)
代码:
int fib(int n) {
if (n == 1 || n == 2) return 1;
return fib(n - 1) + fib(n - 2);
}
六、递归经典案例2:字符串反转
void reverse(char str[], int start, int end) {
if (start >= end) return;
char temp = str[start];
str[start] = str[end];
str[end] = temp;
reverse(str, start + 1, end - 1);
}
七、递归经典案例3:求数组和
int sumArr(int arr[], int len) {
if (len == 0) return 0;
return sumArr(arr, len - 1) + arr[len - 1];
}
八、递归经典案例4:汉诺塔(递归巅峰入门)
汉诺塔是递归最经典、最教科书级案例:
- 把 n 个盘从 A 移到 C
- 借助 B
- 每次只能移一个
- 大盘不能放小盘
void hanoi(int n, char A, char B, char C) {
if (n == 1) {
printf("%c -> %c\n", A, C);
return;
}
hanoi(n - 1, A, C, B);
printf("%c -> %c\n", A, C);
hanoi(n - 1, B, A, C);
}
递归一行解决人类难以模拟的问题。
九、函数嵌套 vs 函数递归(彻底分清)
函数嵌套
- 函数A 调用 函数B
- 不同函数之间调用
- 无自我调用
void a() { b(); }
void b() { }
函数递归
- 函数A 调用自己
- 同一个函数反复执行
- 必须有出口
void a() { a(); }
十、递归底层原理:栈与栈帧
递归为什么会溢出?
- 每调用一次函数,系统就压入一个栈帧
- 递归太深,栈空间不够
- 报错:Stack Overflow
递归深度有限制(一般1万层以内)
大数据量必须改用循环或动态规划。
十一、递归的优缺点
优点
- 代码极简、极优雅
- 逻辑接近数学思维
- 处理树、图、嵌套结构无敌
缺点
- 深度太大栈溢出
- 重复计算(如斐波那契)
- 效率略低于循环
十二、高频致命错误(99%新手必踩)
1)没有终止条件 → 无限递归 → 崩溃
void fun() { fun(); }
2)终止条件写错 → 永远到不了出口
3)递归没有缩小规模 → 死循环
fun(n) → fun(n)
4)递归层次太深 → 栈溢出
5)混淆递去和归来的执行顺序
十三、企业级递归编码规范
- 先写终止条件,再写递归逻辑
- 递归深度不超过1000层
- 高频重复计算用记忆化/动态规划
- 能用递归清晰表达,绝不强行写循环
- 工程中:树遍历、目录遍历、JSON解析、AST语法树大量使用递归
十四、本源级核心总结
- 递归 = 函数自己调用自己
- 必须具备:终止条件 + 规模缩小
- 流程:递去 → 抵达 → 归来
- 递归适合:分治、回溯、树、图、数学公式
- 递归太深会栈溢出
- 递归代码简洁,循环效率更高
- 递归是算法思维的基石
十五、课后实战作业
- 递归求 1~n 的和
- 递归求字符串长度(不使用strlen)
- 递归判断回文字符串
- 递归求最大公约数 gcd
- 递归实现二分查找
下期预告
第18篇我们将进入 局部变量与全局变量:生命周期与访问规则,彻底搞懂C语言变量存哪里、活多久、谁能访问,为后续指针、内存、静态库、模块化打下底层基础!
关注钩子
本专栏为 优快云独家《C语言100篇:从入门到天花板》,100篇永久完整目录、每篇≥2000字高质量原创、底层原理+企业实战全覆盖。
关注 华夏之光永存,从零基础直冲C语言天花板,指针、动态内存、网络、嵌入式、内核全体系一步到位!
412



被折叠的 条评论
为什么被折叠?



