简体   繁体   English

将此递归函数转换为迭代

[英]Convert this recursive function to iterative

How can I convert this recursive function to an iterative function? 如何将此递归函数转换为迭代函数?

#include <cmath>

int M(int H, int T){
    if (H == 0) return T;
    if (H + 1 >= T) return pow(2, T) - 1;
    return M(H - 1, T - 1) + M(H, T - 1) + 1;
}

Well it's a 3-line code but it's very hard for me to convert this to an iterative function. 嗯,它是一个3行代码,但我很难将其转换为迭代函数。 Because it has 2 variables. 因为它有2个变量。 And I don't know anything about Stacks so I couldn't convert that. 我对Stacks一无所知,所以我无法转换它。

My purpose for doing this is speed of the function. 我这样做的目的是提高功能的速度。 This function is too slow. 这个功能太慢了。 I wanted to use map to make this faster but I have 3 variables M , H and T so I couldn't use map 我想使用map来加快速度,但我有3个变量MHT所以我无法使用map

you could use dynamic programming - start from the bottom up when H == 0 and T == 0 calculate M and iterate them. 你可以使用dynamic programming - 当H == 0时自下而上,T == 0计算M并迭代它们。 here is a link explaining how to do this for Fibonacci numbers, which are quite similar to your problem. 这是一个解释如何为Fibonacci数字执行此操作的链接 ,这与您的问题非常相似。

Check this,recursive and not recursive versions gave equal results for all inputs i gave so far. 检查一下,递归和非递归版本为我到目前为止提供的所有输入提供了相同的结果。 The idea is to keep intermediate results in matrix, where H is row index, T is col index, and the value is M(H,T). 我们的想法是将中间结果保存在矩阵中,其中H是行索引,T是col索引,值是M(H,T)。 By the way, you can calculate it once and later just obtain the result from the matrix, so you will have performance O(1) 顺便说一句,你可以计算一次,之后只需从矩阵中获得结果,这样你就会有性能O(1)

int array[10][10]={{0}};

int MNR(int H, int T)
{
    if(array[H][T])
       return array[H][T]; 

    for(int i =0; i<= H;++i)
    {
        for(int j = 0; j<= T;++j)
        {
            if(i == 0)
                array[i][j] = j;

            else if( i+1 > j)
                array[i][j] = pow(2,j) -1;

            else
                array[i][j] = array[i-1][j-1] + array[i][j-1] + 1;

        }
    }

    return array[H][T];
}

int M(int H, int T)
{
    if (H == 0) return T;
    if (H + 1 >= T) return pow(2, T) - 1;
    return M(H - 1, T - 1) + M(H, T - 1) + 1;
}

int main()
{
    printf("%d\n", M(6,3));
    printf("%d\n", MNR(6,3));
}

Unless you know the formula for n-th (in your case, (m,n)-th) element of the sequence, the easiest way is to simulate the recursion using a stack. 除非您知道序列的第n个(在您的情况下,(m,n)-th)元素的公式,否则最简单的方法是使用堆栈模拟递归。

The code should look like the following: 代码应如下所示:

#include <cmath>
#include <stack>

struct Data
{
public:
    Data(int newH, int newT)
        : T(newT), H(newH)
    {

    }

    int H;
    int T;
};

int M(int H, int T)
{
    std::stack<Data> st;

    st.push(Data(H, T));

    int sum = 0;

    while (st.size() > 0)
    {
        Data top = st.top();
        st.pop();

        if (top.H == 0) 
            sum += top.T;
        else if (top.H + 1 >= top.T)
            sum += pow(2, top.T) - 1;
        else
        {
            st.push(Data(top.H - 1, top.T - 1));
            st.push(Data(top.H, top.T - 1));
            sum += 1;
        }
    }

    return sum;
}

The main reason why this function is slow is because it has exponential complexity, and it keeps recalculating the same members again and again. 这个函数速度慢的主要原因是因为它具有指数复杂性,并且它一次又一次地重新计算相同的成员。 One possible cure is memoize pattern (handily explained with examples in C++ here ). 一种可能的解决方法是memoize模式( 这里用C ++中的例子轻松解释)。 The idea is to store every result in a structure with a quick access (eg an array) and every time you need it again, retrieve already precomputed result. 我们的想法是将每个结果存储在具有快速访问权限的结构中(例如,数组),并且每次需要它时,检索已经预先计算的结果。 Of course, this approach is limited by the size of your memory, so it won't work for extremely big numbers... 当然,这种方法受到你的记忆大小的限制,所以它不适用于非常大的数字......

In your case, we could do something like that (keeping the recursion but memoizing the results): 在你的情况下,我们可以做类似的事情(保持递归但记住结果):

#include <cmath>
#include <map>
#include <utility>

std::map<std::pair<int,int>,int> MM;

int M(int H, int T){
    std::pair<int,int> key = std::make_pair(H,T);
    std::map<std::pair<int,int>,int>::iterator found = MM.find(key);
    if (found!=MM.end()) return found->second; // skip the calculations if we can
    int result = 0;
    if (H == 0) result = T;
    else if (H + 1 >= T) result = pow(2, T) - 1;
    else result = M(H - 1, T - 1) + M(H, T - 1) + 1;
    MM[key] = result;
    return result;
}

Regarding time complexity, C++ maps are tree maps, so searching there is of the order of N*log(N) where N is the size of the map (number of results which have been already computed). 关于时间复杂度,C ++映射是树映射,因此在那里搜索N * log(N)的顺序,其中N是映射的大小(已经计算的结果的数量)。 There are also hash maps for C++ which are part of the STL but not part of the standard library, as was already mentioned on SO . 还有C ++的哈希映射,它们是STL的一部分,但不是标准库的一部分,正如SO上已经提到的那样。 Hash map promises constant search time (the value of the constant is not specified though :) ), so you might also give them a try. 哈希映射承诺不断的搜索时间(虽然没有指定常量的值:)),所以你也可以尝试一下。

You may calculate using one demintional array. 您可以使用一个demintional数组计算。 Little theory, 理论不多,

Let F(a,b) == M(H,T)
1. F(0,b) = b
2. F(a,b) = 2^b - 1, when a+1 >= b
3. F(a,b) = F(a-1,b-1) + F(a,b-1) + 1

Let G(x,y) = F(y,x)  ,then
1. G(x,0) = x                 // RULE (1)
2. G(x,y) = 2^x - 1, when y+1 >= x  // RULE (2) 
3. G(x,y) = G(x-1,y-1) + G(x-1,y) + 1  // RULE(3) --> this is useful, 
// because for G(x,y) need only G(x-1,?), i.e if G - is two deminsions array, then 
// for calculating G[x][?]   need only  previous row G[x-1][?], 
// so we need only last two rows of array.

// Here some values of G(x,y)  
4. G(0,y)  = 2^0 - 1 = 0  from (2) rule.
5. G(1,0)  = 1  from (1) rule.
6. G(1,y) = 2^1 - 1 = 1,  when y > 0,  from (2) rule.

G(0,0) = 0,  G(0,1) = 0,   G(0,2) = 0,  G(0,3) = 0  ...
G(1,0) = 1,  G(1,1) = 1,   G(1,2) = 1,  G(1,3) = 1  ...

7. G(2,0) = 2  from (1) rule
8. G(2,1) = 2^2 - 1 = 3   from (2) rule
9. G(2,y) = 2^2 - 1 = 3 when y > 0,  from (2) rule.

G(2,0) = 2,  G(2,1) = 3,  G(2,2) = 3, G(2,3) = 3, ....

10. G(3,0) = 3  from (1) rule
11. G(3,1) = G(2,0) + G(2,1) + 1 = 2 + 3 + 1 = 6  from (3) rule
12. G(3,2) = 2^3 - 1 = 7,  from (2) rule

Now, how to calculate this G(x,y) 现在,如何计算这个G(x,y)

int M(int H, int T ) { return G(T,H); }

int G(int x, int y)
{   
     const int MAX_Y = 100; // or something else
     int arr[2][MAX_Y] = {0} ; 
     int icurr = 0, inext = 1;

     for(int xi = 0; xi < x; ++xi)
     {
          for( int yi = 0; yi <= y ;++yi) 
          {
            if ( yi == 0 )  
                 arr[inext][yi] = xi; // rule (1);
            else if ( yi + 1 >= xi ) 
                 arr[inext][yi] = (1 << xi) - 1; // rule ( 2 )
            else arr[inext][yi] = 
                arr[icurr][yi-1] + arr[icurr][yi] + 1; // rule (3)

          }
          icurr ^= 1; inext ^= 1;          //swap(i1,i2);
     }
     return arr[icurr][y];
}

// Or some optimizing //或者一些优化

int G(int x, int y)
{
    const int MAX_Y = 100;
    int arr[2][MAX_Y] = {0};
    int icurr = 0, inext = 1;

    for(int ix = 0; ix < x; ++ix)
    {
        arr[inext][0] = ix; // rule (1)

        for(int iy = 1; iy < ix - 1; ++ iy) 
            arr[inext][iy] = arr[icurr][iy-1] + arr[icurr][iy] + 1; // rule (3)

        for(int iy = max(0,ix-1); iy <= y; ++iy)
            arr[inext][iy] = (1 << ix ) - 1; // rule(2)

        icurr ^= 1 ; inext ^= 1;
    }

     return arr[icurr][y];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM