递归在C++中确实很慢
Recursion is really that slow in C++?
我知道递归在某些语言中很快(甚至比迭代更快)。但我说的是C++(也许C也是一样的)。
我正在解决一个在线评委问题(不是家庭作业)。我使用自上而下的动态编程方法解决了这个问题。但我最后得了两个TLE。然后,我使用了自下而上的方法,解决方案被接受了。然而,在这个问题中,我认为自上而下应该更快,因为可以进行优化来跳过一些不需要计算的状态。
问题说明:http://www.hkoi.org/training2004/files/need-for-speed.pdf
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
int n, max_t;
int num[51][50001];
int ts[50][50];
int ms[50];
int ls[50];
#ifdef RECURSION
int solve(int rn, int tleft)
{
if (rn >= n)
return 0;
if (num[rn][tleft] != -1)
return num[rn][tleft];
int t;
int max_num = solve(rn + 1, tleft);
for (int i = rn; i < n; ++i)
{
t = ls[i];
for (int j = 0; j < ms[i]; ++j)
{
t += ts[i][j];
if (t > tleft)
break;
max_num = max(max_num, solve(i + 1, tleft - t) + j + 1);
}
}
num[rn][tleft] = max_num;
return max_num;
}
#endif
int main()
{
scanf("%d %d", &n, &max_t);
for (int i = 0; i < n; ++i)
{
scanf("%d %d", ls + i, ms + i);
for (int j = 0; j < ms[i]; ++j)
{
scanf("%d", ts[i] + j);
}
sort(ts[i], ts[i] + ms[i]);
}
for (int i = 0; i <= n; ++i)
{
for (int j = 0; j <= max_t; ++j)
{
#ifdef RECURSION
num[i][j] = -1;
#else
num[i][j] = 0;
#endif
}
}
#ifdef RECURSION
printf("%dn", solve(0, max_t));
#endif
#ifndef RECURSION
int t;
for (int i = n - 1; i >= 0; --i)
{
for (int j = 0; j <= max_t; ++j)
{
t = ls[i];
num[i][j] = num[i + 1][j];
for (int k = 0; k < ms[i]; ++k)
{
t += ts[i][k];
if (t > j)
break;
num[i][j] = max(num[i][j], num[i + 1][j - t] + k + 1);
}
}
}
printf("%dn", num[0][max_t]);
#endif
}
正如您在递归版本中看到的,有一行max_num = max(max_num, solve(i + 1, tleft - t) + j + 1);
。由于t
增加了一个整数,但并不总是=1,因此跳过了某些情况。然而,在迭代版本中,会计算出许多无用的状态。
我认为,如果迭代解决方案更快,那么递归必须比迭代慢得多。我的说法正确吗?
性能优化是一个非常复杂的领域,通常不能将其缩小为简单的建议,例如"迭代比递归快"。
反例发现得很快:例如,大多数最快的排序算法(如Quicksort)通常是递归实现的。
在您的情况下,在实践中,过于频繁地执行一些廉价的操作可能比执行复杂的检查来防止它们快得多,例如,因为缓存未命中较少。判断一个解决方案是否优于另一个的唯一方法是使用探查器进行仔细分析。
看看这个涵盖分支预测的优秀答案(实际上它更像一篇文章):为什么处理排序数组比处理未排序数组更快?
理论上迭代==递归,假设您不使用编译器优化。主要区别在于堆栈中充满了使用递归解决方案的函数调用。然而,递归通常更容易转换为多线程应用程序。此外,如果你有很多if语句,递归解决方案有助于使代码更加抽象,并且你可以在执行过程中非常容易地切换到另一种类型的递归(只需以不同的方式调用函数或调用完全不同的函数)。
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 递归列出所有目录中的C++与Python与Ruby的性能
- 递归计数给定目录的文件和所有目录
- 如何在BST的这个简单递归实现中消除警告
- C++:正在检查LinkedList中的回文-递归方法-错误
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 递归无序映射
- TSP递归解的迭代形式
- 如何在Elixir中调用递归函数并行
- 返回递归调用和仅递归调用的区别
- 数组元素打印的递归方法
- 使用递归时获取变量的奇怪值
- 如何在C++中递归地按相反顺序打印集合
- 到连接组件算法的问题(递归)
- 如何使用递归打印修改后的星号三角形图案
- 使用递归模板动态分配的多维数组
- 递归函数有效,但无法记忆
- 包含模板文件的递归会导致编译失败