C语言函数递归详解:递归条件、调用过程与迭代对比

C语言函数递归详解:递归条件、调用过程与迭代对比
LichermioneC语言函数递归详解
1. 递归是什么
递归是函数直接或间接调用自身,把复杂问题不断缩小为结构相同的子问题。
一个正确的递归通常包含:
- 基准条件:在某种情况下停止递归;
- 递推关系:把当前问题转化为规模更小的问题;
- 规模收敛:每次调用都必须靠近基准条件。
2. 阶乘
数学定义:
1 | 0! = 1 |
1 | long long factorial(int n) |
计算 factorial(4) 时,调用逐层展开:
1 | factorial(4) |
遇到基准条件后,再逐层返回结果。
3. 递归打印整数
1 | void print_digits(unsigned int n) |
输入 1234 时,先递归处理高位,再在回归阶段从高位到低位输出。
4. 递归求字符串长度
1 | size_t string_length(const char *str) |
每次把指针移动到下一个字符,直到遇到字符串结束标志 \0。
5. 递归与迭代
阶乘的迭代版本:
1 | long long factorial_iterative(int n) |
| 对比项 | 递归 | 迭代 |
|---|---|---|
| 表达能力 | 接近数学定义,适合树与分治 | 流程直接 |
| 空间 | 消耗调用栈 | 通常为常量额外空间 |
| 风险 | 递归过深可能栈溢出 | 较少出现栈深问题 |
| 性能 | 有函数调用开销 | 通常更高效 |
6. 斐波那契数列的陷阱
朴素递归:
1 | long long fib(int n) |
它会重复计算大量子问题,时间复杂度接近指数级。迭代写法更合适:
1 | long long fib_iterative(int n) |
7. 常见问题
- 没有基准条件,导致无限递归;
- 问题规模没有缩小,永远无法到达出口;
- 递归层数太深,引发栈溢出;
- 在递归中进行重复计算,导致性能极差;
- 忽略负数、溢出等输入边界。
8. 适用场景
递归适合具有天然层次结构的问题,例如二叉树遍历、目录遍历、回溯、快速排序和归并排序。对于简单线性重复,循环通常更直接、更稳定。
9. 总结
理解递归要同时看到“向下展开”和“向上回归”。写递归前先明确出口、递推关系和规模变化,再评估调用深度与重复计算成本。