【问题标题】:Best way to write a recursive function in C++?用 C++ 编写递归函数的最佳方法?
【发布时间】:2011-03-05 11:12:55
【问题描述】:

问题
我想知道这是否是实现可变深度递归的可行方法,以便我可以在每一步运行一个函数以及描述问题的任何更好/其他解决方案。
描述
假设我希望有一个函数以模式填充数组
x,y,x,y,x,y其中 x 和 y 是由某些算法定义的变量
x,y,z,x,y,z 其中x、y 和z 是由相同算法定义的变量。

这应该对所有数量的变量继续。这是一种可行的实施方式吗?

void recurse_n(int n)
{
    while(n > 0)
    {
        --n;
        recurse_n(n);
        n = 0;
        // Use algorithm here
    }
}

编辑:删除了之前提到的不正确的返回类型。脑残。

【问题讨论】:

  • 这不是一个无限循环,因为 recurse_n 总是会在到达 0 之前被调用
  • @PowerRoy:不,这不是无限循环。如果 n 为 0 或更小,则不会递归。如果 n 大于 0,就会有递归,但是对于每次递归,n 会更小,所以它总是会达到 0 的基本情况。
  • 不,这不是一个无限循环,因为在调用 recurse_n 之前 n 会递减,所以最终它会以 0 的参数被调用。追溯调用堆栈,它们将各自结束,因为一旦 recurse_n返回它会将 n 设置为 0 并跳出循环。
  • 您是在寻求帮助以定义创建序列 x、y、x、y、x、y 等的算法,还是在询问如何设置递归函数?
  • 这不是递归的好用法,IMO。好像有点矫枉过正。你最好只使用某种循环......

标签: c++ algorithm function recursion


【解决方案1】:

我对这个问题有点不清楚,但听起来您有一组变量a, b, c, ..., z,并且您想填充一个数组以使其包含a, b, c, ..., z, a, b, c, ..., z, a, ...。如果是这样,最简单的方法可能是将源变量放在他们自己的一次性数组a, b, c, ..., zmemcpy 中,直到它被填充到目标数组中

#define NUM 3
int a, b, c; // source variables
void fill(int* arr, unsigned int size) {
    int src[] = {a, b, c};
    unsigned int i;
    for(i = 0; i < size / NUM; i++)
        memcpy(arr + (NUM * i), src, sizeof(int) * NUM);
    memcpy(arr + (NUM * i), src, sizeof(int) * (size % NUM));
}

【讨论】:

  • 具体来说,我希望生成均匀分布(某种)的云坐标,表示一个 n 立方体并将它们存储在一维数组中,但是我只需要一种方法来实现递归在运行时设置的深度。
【解决方案2】:

我不认为这是一种可行的方法,因为:让T(n) 表示函数的运行时间(取决于输入参数n)。

基本情况n=0 产生以下运行时间:T(0)=c,即一些恒定运行时间c

现在您可以为运行时间定义一个递归公式,其中n&gt;0T(n)=sum(i = 0 to n-1: T(i))

如果你解决这个方程,你会得到T(n)=O(2^n),这意味着你的算法是指数的,这意味着它在实践中是不可处理的。

【讨论】:

  • 这是否也意味着通过编写嵌套的 for 循环来实现这一点也会导致指数算法,这意味着这是一个已知问题,随着维度的增加,运行时间会增加,而这只需要在处理大量维度时被接受?
【解决方案3】:

因此,根据您的评论,您想知道设置递归函数的最佳方法。您所做的将起作用,但它令人费解且略显混乱。我会做的是简化它:

void recurse_n(int n) {
    if (n <= 0) {
        // Break-out condition
        return;
    }

    --n;
    recurse_n(n);

    // Your algorithm stuff here.
}

这将使您更容易看到正在发生的事情。我要补充的一件事是,您可能希望在调用 recurse_n 之前执行算法操作,但这完全取决于您的算法在做什么。

如果您考虑一下,按照我编写的方式,它会递归直到 n 小于或等于 0,然后再执行任何算法工作。可能是您想要做算法工作然后递归。

【讨论】:

  • 谢谢,这就是我所追求的,并确认这是正确的代码。希望我们能在这个问题消失之前就复杂性等问题进行更多讨论,并得到一个公认的答案。
【解决方案4】:

首先,使用 std::vector 和循环(我假设 x()、y() 和 z() 返回您需要的 ints,您也可以在那里使用向量来存储值):

void fill( std::vector<int> &vec, std::vector<int> &values )
{
    size_t nValues = values.size();
    size_t sz = vec.size();
    for( size_t i=0; i<sz; i=i+nValues )
    {
        for( size_t j=0; j<nValues; ++j )
        {
            vec[i] = values[j];
        }
    }
}

int main()
{
    std::vector<int> vec;
    std::vector<int> values;
    /* fill values vector here */
    vec.resize( 512 ); // (arbitraty) size you need
    fill( vec, values );

    return 0;
}

这比递归函数更接近 C++ 并且速度更快。另外:存储 x、y 和 z 值,以便相应的算法只执行一次。

【讨论】:

  • 这并没有真正的帮助,因为您的填充矢量算法只能填充 x 和 y。我想要一个可以填充任意数量维度的通用型。不仅仅是二维。
  • 我更新了我的答案。可能有更好的方法,避免第二个循环,但这已经是 O(n²),恕我直言,这是可能的最低复杂度(如果我错了,请有人纠正我)
  • 谢谢。现在已经相当不错了。
  • 除了什么都不做(几个错别字)之外,更简单的方法是这样的:for (size_t i = 0, j = 0; i &lt; sz; ++i, j = (j + 1) % values.size()) vec[i] = values[j];
  • 我得到了全部吗? :s 我没有冒昧使用你的 % 变体,那会偷窃 ;)
【解决方案5】:

JimDaniel 是对的,这里的递归有点矫枉过正。您没有从函数返回任何内容,看起来您只是使用“n”来控制递归次数。使用简单的 for 循环会更清晰 + 更高效。

【讨论】:

    【解决方案6】:

    如果您的算法满足以下要求,则使用递归填充数组是一个有效(甚至是最好的)选项:

    1. n 位置的值至少取决于它之前的一些值的值
    2. 没有(已知的)方法可以确定位置 n 的值,除非先确定它所依赖的早期值。

    满足这些要求的一个示例是fibonacci numbers。因为如果不先确定所有较早的数字,就无法确定第 n 个数字(尽管存在一些捷径)。

    一个不符合这些要求的例子是一个用索引的平方填充的数组,其中n 位置的值就是n^2

    最后,如果可能,我建议您根据 DaveJohnston 对您问题的回答中的模式重写您的函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 2014-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-11
      相关资源
      最近更新 更多