梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
递归在数学问题中应用极广,因为阶乘、斐波那契、组合 / 排列数 这类数学公式本身就具备「递归定义」的特征,用递归实现的代码简洁易懂、逻辑和数学公式完全一致,非常适合入门学习递归的核心用法。以下是 4 个典型实例:
递归核心要素
问题描述:
算法解析:
#include <iostream>
using namespace std;
// 迭代计算n的阶乘
long long factorial_iter(int n) {
long long sum =1;
for(int i=n;i>0;i--) {
sum = sum * i;
}
return sum;
}
// 递归计算n的阶乘
long long factorial_recu(int n) {
// 1. 递归终止条件(基准条件)
if (n == 0) {
return 1;
}
// 2. 递归公式:大问题拆解为小问题
return n * factorial_recu(n - 1);
}
int main() {
int n;
cout << "请输入一个非负整数n:";
cin >> n;
if (n < 0) {
cout << "错误:阶乘仅支持非负整数!" << endl;
} else {
cout << "迭代计算" << n << "! = " << factorial_iter(n) << endl;
cout << "递归计算" << n << "! = " << factorial_recu(n) << endl;
}
return 0;
}
请输入一个非负整数n:5
迭代计算5! = 120
递归计算5! = 120
斐波那契数列---这个数列从第三项开始,每一项都等于前两项之和。
斐波那契数列是递归的经典应用,也是动态规划的前置案例,能直观看到递归的优缺点。
问题描述:
数列:0, 1, 1, 2, 3, 5, 8, 13, 21, ...
算法解析:
#include <iostream>
using namespace std;
// 迭代计算斐波那契数列第n项(动态规划)
long long fibonacci_iter(int n) {
long long up1 =0;
long long up2 =1;
long long sum =0;
for(int i=2; i <= n; i++) {
sum = up1 + up2;
//更新前两项
up1 = up2;
up2 = sum;
}
if(n == 0) sum = up1;
if(n == 1) sum = up2;
return sum;
}
// 递归计算斐波那契数列第n项
long long fibonacci_recu(int n) {
// 1. 递归终止条件
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
}
// 2. 递归公式
return fibonacci_recu(n - 1) + fibonacci_recu(n - 2);
}
int main() {
int n;
cout << "请输入斐波那契数列的项数n:";
cin >> n;
if (n < 0) {
cout << "错误:项数不能为负数!" << endl;
} else {
cout << "迭代计算斐波那契数列第" << n << "项 = " << fibonacci_iter(n) << endl;
cout << "递归计算斐波那契数列第" << n << "项 = " << fibonacci_recu(n) << endl;
}
return 0;
}
请输入斐波那契数列的项数n:10
迭代计算斐波那契数列第10项 = 55
递归计算斐波那契数列第10项 = 55
问题描述:
算法解析:
从 n 个元素中选 k 个,分为两种情况:
#include <iostream>
using namespace std;
// 迭代计算n的阶乘
long long factorial_iter(int n) {
long long sum =1;
for(int i=n;i>0;i--) {
sum = sum * i;
}
return sum;
}
// 递归计算n的阶乘
long long factorial_recu(int n) {
// 1. 递归终止条件(基准条件)
if (n == 0) {
return 1;
}
// 2. 递归公式:大问题拆解为小问题
return n * factorial_recu(n - 1);
}
// 迭代计算组合数(杨辉三角)
long long combination_iter(int n, int k) {
// 边界条件:非法输入返回0
if (k < 0 || k > n) return 0;
if (k == 0 || k == n) return 1;
// 创建二维数组存储杨辉三角,dp[i][j] 表示 C(i,j)
vector<vector<long long>> dp(n + 1, vector<long long>(n + 1, 0));
// 初始化第0行
dp[0][0] = 1;
// 迭代生成每一行
for (int i = 1; i <= n; ++i) {
dp[i][0] = 1; // 每行第一个数为1
dp[i][i] = 1; // 每行最后一个数为1
// 计算中间的数
for (int j = 1; j < i; ++j) {
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
}
}
return dp[n][k];
}
// 递归计算组合数(杨辉三角)
long long combination_recu(int n, int k) {
// 1. 递归终止条件
if (k == 0 || k == n) {
return 1;
}
if (k > n) {
return 0;
}
// 2. 递归公式:C(n,k) = C(n-1,k-1) + C(n-1,k)
return combination_recu(n - 1, k - 1) + combination_recu(n - 1, k);
}
// 迭代计算组合数(直接乘积法)
long long combination_product(int n, int k) {
if (k < 0 || k > n) return 0;
if (k == 0 || k == n) return 1;
k = min(k, n - k);
// 优化计算:直接计算乘积形式,避免阶乘
long long res = 1;
for (int i = 1; i <= k; ++i) {
// 分步乘除,避免中间结果溢出(比如先乘 n-k+i,再除以 i)
res = res * (n - k + i) / i;
}
return res;
}
int main() {
int n, k;
cout << "请输入n和k(计算C(n,k)):";
cin >> n >> k;
if (n < 0 || k < 0) {
cout << "错误:n和k必须为非负整数!" << endl;
} else {
cout << "算法一迭代实现:C(" << n << "," << k << ") = " << factorial_iter(n) / ( factorial_iter(k) * ( factorial_iter(n - k) ) ) << endl;
cout << "算法一递归实现:C(" << n << "," << k << ") = " << factorial_recu(n) / ( factorial_recu(k) * ( factorial_recu(n - k) ) ) << endl;
cout << "算法二迭代实现:C(" << n << "," << k << ") = " << combination_iter(n, k) << endl;
cout << "算法二递归实现:C(" << n << "," << k << ") = " << combination_recu(n, k) << endl;
cout << "算法三迭代实现:C(" << n << "," << k << ") = " << combination_product(n, k) << endl;
}
return 0;
}
请输入n和k(计算C(n,k)):5 3
算法一迭代实现:C(5,3) = 10
算法一递归实现:C(5,3) = 10
算法二迭代实现:C(5,3) = 10
算法二递归实现:C(5,3) = 10
问题描述:
算法解析:
#include <iostream>
using namespace std;
// 迭代计算n的阶乘
long long factorial_iter(int n) {
long long sum =1;
for(int i=n;i>0;i--) {
sum = sum * i;
}
return sum;
}
// 递归计算n的阶乘
long long factorial_recu(int n) {
// 1. 递归终止条件(基准条件)
if (n == 0) {
return 1;
}
// 2. 递归公式:大问题拆解为小问题
return n * factorial_recu(n - 1);
}
// 迭代计算排列数 A(n,k)
long long permutation_iter(int n, int k) {
if (k < 0 || k > n) return 0;
if (k == 0) return 1;
long long res = 1;
// 递进计算:n*(n-1)*...*(n-k+1)
for (int i = 0; i < k; ++i) {
res = res * (n - i);
}
return res;
}
// 递归计算排列数 A(n,k)
long long permutation_recu(int n, int k) {
// 1. 递归终止条件
if (k == 0) {
return 1;
}
if (k > n) {
return 0;
}
// 2. 递归公式
return n * permutation_recu(n - 1, k - 1);
}
int main() {
int n, k;
cout << "请输入n和k(计算A(n,k)):";
cin >> n >> k;
if (n < 0 || k < 0) {
cout << "错误:n和k必须为非负整数!" << endl;
} else {
cout << "算法一迭代实现:A(" << n << "," << k << ") = " << factorial_iter(n) / factorial_iter(n - k) << endl;
cout << "算法一递归实现:A(" << n << "," << k << ") = " << factorial_recu(n) / factorial_recu(n - k) << endl;
cout << "算法二迭代实现:A(" << n << "," << k << ") = " << permutation_iter(n, k) << endl;
cout << "算法二递归实现:A(" << n << "," << k << ") = " << permutation_recu(n, k) << endl;
}
return 0;
}
请输入n和m(计算A(n,k)):5 2
算法一迭代实现:(5,2) = 20
算法一递归实现:(5,2) = 20
算法二迭代实现:(5,2) = 20
算法二递归实现:(5,2) = 20
结合本文的 4 个数学实例,总结递归在求解数学问题时的优缺点
优点
缺点
在数学问题中,优先使用递归的场景: