使用地图进行记忆

时间:2018-09-28 04:56:54

标签: c++ dictionary recursion data-structures memoization

我正在尝试使用map优化递归问题以处理运行时错误。但是,使用记忆方法和实现地图仍然不能完全解决问题。通过使用简单的递归方法,直到totalNum = 36才显示分段错误。优化之后,当totalNum变得很大时(例如99999),分段错误仍然会出现。 即使totalNum大于99999,有什么方法可以解决此运行时问题吗?以下是我的头文件代码:

using namespace std; 
static map<pair<int, int>, double> map;

double val(int r, int b){   
if (0 == r)
    return ((double) b);
if (0 == b)
    return (0);
if (map.find(make_pair(r, b)) != map.end()){
    return (double)map[make_pair(r, b)];
} else{
    double num1 = ((double) r/(r+b)) * value(r-1, b);
    double num2 = ((double) b/(r+b)) * value(r, b-1);
    double value = max((num1 + num2), (double) (b - r));
    map[make_pair(r, b)] = value;
    return value;
}
}

#endif

在main()中用于打印消息:cout <<“ Value =” << val(totalNum / 2,totalNum / 2)<< endl;

2 个答案:

答案 0 :(得分:1)

  

即使totalNum大于99999,有什么方法可以解决此运行时问题吗?   摆脱递归。很容易找出计算值(r, b)所需的值。您可以使用循环来计算它们。

递归版本的问题在于它需要大量的堆栈空间,这是非常有限的。因此,此解决方案无法扩展。备注不会改变这一点,因为函数参数和返回值仍需要保存在堆栈中。即使可以优化递归(通常仅使用尾递归),未优化的构建仍然无法运行。这可能意味着您无法有效地调试程序。

更改为循环时,可以将堆栈空间重新用于函数参数并将结果存储在堆中。

答案 1 :(得分:0)

优化(和记忆,作为一种优化技术)用于将慢速代码转换为更快的代码,而不是将易于出错的代码转换为无错误的代码。

很有可能您的段错误(请参见Wiki上的common causes)与备注无关。当然,添加备注可以更改段错误的频率和行为,但这并没有导致它也没有将其删除。

segfault的最常见原因是尝试使用已释放的指针(在C ++中为delete d),但是您的代码无法直接处理任何原始指针,因此可能不是原因。

segfault的第二个最常见原因是返回对局部变量的引用,在这种情况下也不会发生这种情况。

但是,因为在记忆后,段错误发生的次数更大(总数),所以它可能与堆栈大小有关。在C ++中,递归通常会导致堆栈使用量始终增加,并且您可以轻松用完操作系统通常提供的所有堆栈(导致堆栈溢出,通常以段错误的形式发出信号)。这可能是细分错误的根源。如果您使用的是Linux,请尝试使用ulimit -s来查看当前的堆栈大小,然后粗暴地增加它(通过对64 Mb的堆栈使用ulimit -s 65536之类的东西)来查看是否使您在totalNum。如果是这样,那么您现在知道问题出在堆栈溢出。 Then it will be easier to find solutions for it。因此,无错误的解决方案是将递归算法更改为基于任务的算法(即,设置要处理的值队列,循环遍历和处理其中的项目,而不使用递归。

否则,最好查看更多代码,因为此段错误不太可能是由此备注代码引起的。

此外,如果您提供一个最小的工作示例,一个虚拟的main函数以及所有编译所需的东西,那将非常好。