【问题标题】:Undoing a recursion tree撤消递归树
【发布时间】:2015-10-24 21:42:11
【问题描述】:

SHORT我应该如何减少(优化)代码中所需操作的数量?

更长 为了研究,我用 C++ 编写了一组方程,如果它适合模型,则输出一个序列。在代码的最里面是这个函数,在运行时被调用了很多次:

int Weight(int i, int q, int d){
    int j, sum = 0;
    if (i <= 0)
        return 0;
    else if (i == 1)
        return 1;
    for (j = 1; j <= d; j++){
        sum += Weight((i - j), q, d);
    }
    sum = 1 + ((q - 1) * sum);
    return sum;
}

所以根据变量d的大小,索引i的大小,以及其余代码中这个函数被调用的次数,做了很多冗余计算。我应该如何减少计算次数?

理想情况下,例如,在计算 Weight(5, 3, 1) 之后,如果函数是递归定义的,我如何告诉计算机在调用 Weight(6, 3, 1) 时替换它的值而不是重新计算它的值?

在这种情况下多维向量是否可以存储值?我应该将值打印到要读取的文件吗?我还没有遇到我给它的输入大小溢出,但是尾递归有助于优化它吗?

注意:我仍在学习如何编程,我很惊讶我什至能够在一开始就正确地制作模型。

【问题讨论】:

  • 您熟悉动态编程或记忆化吗?
  • @templatetypedef 我多次听说过动态编程,但仍然不确定它的含义。从它的样子来看,记忆是一个流行的答案,可能只是一个查找表,所以这就是我要首先尝试的。

标签: c++ optimization recursion memoization


【解决方案1】:

你可以使用记忆化

int WeightImpl(int i, int q, int d); // forward declaration

// Use memoization and use `WeightImpl` for the real computation
int Weight(int i, int q, int d){
    static std::map<std::tuple<int, int, int>, int> memo;

    auto it = memo.find(std::make_tuple(i, q, d));
    if (it != memo.end()) {
        return it->second;
    }
    const int res = WeightImpl(i, q, d);
    memo[std::make_tuple(i, q, d)] = res;
    return res;
}

// Do the real computation
int WeightImpl(int i, int q, int d){
    int j, sum = 0;
    if (i <= 0)
        return 0;
    else if (i == 1)
        return 1;
    for (j = 1; j <= d; j++){
        sum += Weight((i - j), q, d); // Call the memoize version to save intermediate result
    }
    sum = 1 + ((q - 1) * sum);
    return sum;
}

Live Demo

注意:当您使用递归调用时,您必须谨慎调用哪个版本才能真正记住每个中间计算。我的意思是递归函数应该被修改为不调用自身,而是调用函数的 memoize 版本。对于非递归函数,可以在不修改实际函数的情况下进行记忆。

【讨论】:

  • 需要注意的是,std::map 可能会根据问题被更高效的数据结构代替。但这无疑是一种很好的简单方法,可以确定是否真的值得花时间在这种方法上。
  • @stefan 我复制并粘贴了您的代码,但弹出了一些错误。值得注意的是,“备忘录未定义”“'it' 在初始化之前不能使用”和“'.end' 的左侧必须有类/结构/联合。”我非常感谢您为帮助我所做的努力,尽管到目前为止!在复制和粘贴之前,我尝试了 memoization 并将权重存储在一个全局数组中,这将计算速度提高了大约 10%。
【解决方案2】:

您可以使用数组来存储中间值。例如,对于某些 d 和 q 有一个数组,其中包含索引 i 处的 Weight(i, q, d) 的值。

如果将数组项初始化为 -1,则可以在函数中执行例如

if(sum_array[i] != -1){    // if the value is pre-calculated
    sum += sum_array[i];
}
else{
    sum += Weight((i - j), q, d);
}

【讨论】:

    猜你喜欢
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 2011-07-24
    • 2016-04-19
    • 2017-01-14
    相关资源
    最近更新 更多