1. 基本概念
递归:函数直接或间接调用自身的方法
-
需要有明确的终止条件
-
每次调用会创建新的栈帧
-
简洁但可能效率较低
迭代:使用循环结构(for、while、do-while)重复执行的方法
-
在同一个栈帧中执行
-
通常效率更高,但代码可能较长
2. 代码示例对比
2.1 计算阶乘
#include <iostream>
using namespace std;
// 递归实现
int factorial_recursive(int n) {
if (n <= 1) // 终止条件
return 1;
return n * factorial_recursive(n - 1); // 递归调用
}
// 迭代实现
int factorial_iterative(int n) {
int result = 1;
for (int i = 1; i <= n; i++) { // 循环迭代
result *= i;
}
return result;
}
2.2 斐波那契数列
// 递归实现
int fibonacci_recursive(int n) {
if (n <= 1) // 终止条件
return n;
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2); // 双重递归
}
// 迭代实现
int fibonacci_iterative(int n) {
if (n <= 1) return n;
int a = 0, b = 1, c;
for (int i = 2; i <= n; i++) { // 循环迭代
c = a + b;
a = b;
b = c;
}
return b;
}
2.3 遍历二叉树
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 递归实现
void inorder_recursive(TreeNode* root) {
if (!root) return; // 终止条件
inorder_recursive(root->left); // 递归左子树
cout << root->val << " "; // 访问节点
inorder_recursive(root->right); // 递归右子树
}
// 迭代实现(使用栈)
#include <stack>
void inorder_iterative(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* curr = root;
while (curr || !st.empty()) { // 循环迭代
// 左子树入栈
while (curr) {
st.push(curr);
curr = curr->left;
}
// 访问节点
curr = st.top();
st.pop();
cout << curr->val << " ";
// 处理右子树
curr = curr->right;
}
}
3. 对比表格
| 特性 | 递归 | 迭代 |
|---|---|---|
| 实现方式 | 函数调用自身 | 循环结构 |
| 内存使用 | 栈帧开销大,可能栈溢出 | 栈帧开销小 |
| 代码可读性 | 简洁优雅,接近数学定义 | 可能较复杂 |
| 性能 | 函数调用开销大 | 通常更高效 |
| 调试难度 | 较难跟踪执行流程 | 较容易调试 |
| 适用场景 | 树遍历、分治、回溯等 | 大部分循环场景 |
4. 选择建议
使用递归的情况:
-
问题具有递归定义(如树结构、分治算法)
-
代码简洁性更重要
-
递归深度有限制(不会栈溢出)
使用迭代的情况:
-
性能要求严格
-
递归深度可能很大
-
需要控制内存使用
5. 性能对比测试
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
int main() {
int n = 40; // 计算斐波那契数列第40项
// 测试递归性能
auto start1 = high_resolution_clock::now();
int fib_rec = fibonacci_recursive(n);
auto end1 = high_resolution_clock::now();
auto duration1 = duration_cast<milliseconds>(end1 - start1);
// 测试迭代性能
auto start2 = high_resolution_clock::now();
int fib_iter = fibonacci_iterative(n);
auto end2 = high_resolution_clock::now();
auto duration2 = duration_cast<microseconds>(end2 - start2);
cout << "斐波那契数列第" << n << "项:" << endl;
cout << "递归方法:" << fib_rec << ",耗时:" << duration1.count() << "ms" << endl;
cout << "迭代方法:" << fib_iter << ",耗时:" << duration2.count() << "μs" << endl;
return 0;
}
6. 尾递归优化
某些编译器会对尾递归进行优化,将其转换为迭代:
// 普通递归
int sum_recursive(int n) {
if (n <= 0) return 0;
return n + sum_recursive(n - 1); // 非尾递归
}
// 尾递归
int sum_tail_recursive(int n, int acc = 0) {
if (n <= 0) return acc;
return sum_tail_recursive(n - 1, acc + n); // 尾递归,可被优化
}
总结
在C/C++中,递归 和迭代是解决问题的两种不同思维方式:
-
递归更符合某些问题的自然结构,但可能有性能问题
-
迭代通常更高效,但代码可能不够直观
-
实际开发中应根据具体需求、性能要求和代码可维护性来选择