撤消递归树

Undoing a recursion tree

本文关键字:递归 撤消      更新时间:2023-10-16

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

LONGER为了研究,我用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)时,我如何告诉计算机替换它的值而不是重新计算它的值?

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

注意:我仍然在学习如何编程,我很惊讶我甚至能够在第一个地方得到正确的模型。

你可以使用记忆法

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;
}

现场演示

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

可以使用数组来存储中间值。例如,对于特定的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);
}