递归,简单来说就是一个函数调用自己。听起来是不是有点疯狂?别急,用生活中的例子来理解:
递归有两个必要条件:
5! = 5 × 4!,4! = 4 × 3!,……,1! = 1(出口!)5! = 5 × 4 × 3 × 2 × 1 = 120
递归的核心思想:把大问题分解为结构相同的更小问题,直到问题小到可以直接回答。
示例 1:用递归求阶乘
1// 递归求阶乘 n!
2int factorial(int n) {
3 // 递归出口:0! = 1, 1! = 1
4 if (n == 0 || n == 1) return 1;
5
6 // 递归调用:n! = n × (n-1)!
7 return n * factorial(n - 1);
8}
9
10int main() {
11 cout << factorial(5); // 输出: 120
12 return 0;
13}
示例 2:斐波那契数列
1// 递归求斐波那契数列
2// F(1)=1, F(2)=1, F(n)=F(n-1)+F(n-2)
3int fib(int n) {
4 // 递归出口
5 if (n <= 2) return 1;
6
7 // 递归调用:拆成两个更小的子问题
8 return fib(n - 1) + fib(n - 2);
9}
10
11int main() {
12 for (int i = 1; i <= 10; i++)
13 cout << fib(i) << " ";
14 // 输出: 1 1 2 3 5 8 13 21 34 55
15 return 0;
16}
int f(int n) { if(n==1) return 1; return n + f(n-1); }f(4) 结果是?最常见的错误!没有出口会导致函数无限调用自己,最终 Stack Overflow 崩溃。写递归第一步就是先写 if 出口。
比如阶乘应该在 n == 1 时返回,但写成了 n == 0——虽然数学上 0!=1,但如果递推是 n×f(n-1),当 n=1 时会调用 f(0),f(0) 又调用 f(-1)……一路调下去就爆了。务必确保每次调用都向出口靠近。
朴素递归(如斐波那契)会有大量重复计算。考试中如果数据范围大(n > 30),需要记忆化或改成递推(用循环 + 数组)。
递归是"自顶向下"调用自己;递推是"自底向上"用循环逐步计算。两者可以互相转换,但递推通常更快、更省内存。考试中灵活选择即可。
hanoi(int n, char from, char mid, char to) 函数,并在 main 中调用 hanoi(3, 'A', 'B', 'C')。#include <iostream>
using namespace std;
void hanoi(int n, char from, char mid, char to) {
if (n == 1) {
cout << from << " → " << to << endl;
return;
}
hanoi(n - 1, from, to, mid); // 先把 n-1 个盘子移到 B
cout << from << " → " << to << endl; // 移最大的到 C
hanoi(n - 1, mid, from, to); // 再把 n-1 个盘子从 B 移到 C
}
int main() {
hanoi(3, 'A', 'B', 'C');
return 0;
}
// 输出:
// A → C
// A → B
// C → B
// A → C
// B → A
// B → C
// A → C