【问题标题】:Writing a recursive function iteratively迭代地编写递归函数
【发布时间】:2012-10-15 18:11:29
【问题描述】:

我最近才开始学习递归,在某个特定的练习上遇到了一些麻烦;从递归状态迭代地重写函数,特别是在涉及多个基本情况时:

double function(int j, int i)
{
    if(i == 0 || j == 1)
    {
        return 1;
    }

    if(i == 1 || j == 0)
    {
        return j;
    }

    if(i > 0)
    {
        return j * function(j, --i);
    }

    return 1 / (function(j, -i))
}

我在迭代地重写函数时遇到了麻烦。

【问题讨论】:

  • 你想要源代码,还是只想要基本的想法?
  • 你想做什么?你面临什么麻烦?将其添加到您的问题中
  • 电话function(4, -1) 永远不会结束。
  • @jplot:我认为最后一行应该是return 1 / (function(j, -i));
  • 迭代是什么意思?你的意思是使用循环?

标签: c++ recursion iteration


【解决方案1】:

首先,这是你的代码压缩(我这样做是为了回答,不要在实际代码中这样做。)

double function(int j, int i) {
    if(i == 0 || j == 1) return 1;
    if(i == 1 || j == 0) return j;
    if(i > 0) return j * function(j, --i);
    return 1 / (function(j, -i)); //changed this to -i
     //might be a division by zero, you should check for that
}

由于最后一个块只能有效地发生在最外层的循环中,我们将把它拉出来:

double outer_function(int j, int i) {
    if (i<0)
        return 1 / inner_function(j, -i);
    else
        return inner_function(j, i);
}
double inner_function(int j, int i) {
    if(i == 0 || j == 1) return 1;
    if(i == 1 || j == 0) return j;
    if(i > 0) return j * inner_function(j, --i);
}

我要做的第一件事是尝试将其放入尾递归形式。这涉及重新排列方程,因此递归之后没有任何内容。 (我不是 100% 确定我做对了这一步)

double inner_function(int j, int i, int times=1) {
    if(i == 0 || j == 1) return times;
    if(i == 1 || j == 0) return times*j;
    return inner_function(j, --i, times*j);
}

现在,由于在每个代码路径中都没有函数调用之后的代码,所以这是完全尾递归的。尾递归很容易改成迭代!

double inner_function(int j, int i, int times=1) {
    while(true) {
        if(i == 0 || j == 1) return times;
        if(i == 1 || j == 0) return times*j;
        //return inner_function(j, --i, times*j);
        --i;
        times *= j;
        //go again!
    }
}

如果我从这里开始优化:

double function(int j, int i) {
    bool invert = false;
    if(i<0) {
         i=-i; 
         invert=true;
    }
    double result=1;
    if(i == 0) result = 0;
    else if(j == 0) result = j;
    else if (j != 1) {
        while(i--)
            result *= j;
    }
    return (invert ? 1/result : result);            
}

或者,如果我猜你的意图:

double function(int j, int i) {
    return std::pow(double(j), double(i));
}

【讨论】:

    【解决方案2】:

    在递归期间你真的只有一个基本情况。 j 永远不会改变,所以它只是一开始的特例。 i 在第一次递归调用后将始终为正并趋向 0。所以唯一真正的基本情况是i == 1

    函数的开头可以保持不变。

    double function(int j, int i)
    {
        if(i == 0 || j == 1) { return 1; }
        if(i == 1 || j == 0) { return j; }
    

    现在您只需要处理i &gt; 0i &lt; 0 的情况(i == 0 一开始就已经处理好了)。

    这两种情况的区别在于,如果i为负数,则切换符号并反转结果。

        int invert = i < 0;
        i = abs(i); // or: if (i < 0) { i = -i; }
    

    现在看看递归部分并弄清楚发生了什么。

    return j * function(j, --i);
    

    function() 将被调用,直到 i 为 1,此时的结果将为 j。每次迭代都会将返回值乘以j。可以这样写:

        double returnValue = j; // (the i == 1 case)
    
        while (i-- > 1) { // loop while i is greater than 1
            returnValue = j * returnValue; // multiply j by the return value
        }
    

    如果需要,现在反转并返回结果。

        if (invert) {
            returnValue = 1 / returnValue;
        }
        return returnValue;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-22
      • 2012-07-01
      • 2021-06-08
      • 2019-04-03
      • 2016-03-01
      • 2021-12-31
      • 1970-01-01
      • 2012-10-17
      • 2021-12-09
      相关资源
      最近更新 更多