将此递归功能转换为迭代
Convert this recursive function to iterative
如何将此递归函数转换为迭代函数?
#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;
}
好吧,这是一个3线代码,但是我很难将其转换为迭代功能。因为它有2个变量。我对Stacks
一无所知,所以我无法转换。
我这样做的目的是功能的速度。此功能太慢。我想使用 map
来更快地使它更快,但是我有3个变量M
,H
和T
,因此我无法使用map
您可以使用 dynamic programming
-从h == 0和t == 0计算m并迭代它们时从底部开始。这是一个链接,解释了如何对斐波那契数字执行此操作,这与您的问题非常相似。
检查此内容,递归而不是递归版本给出了我到目前为止给出的所有输入的结果。这个想法是将中间结果保持在矩阵中,其中H是行索引,t为col索引,值为m(h,t)。顺便说一句,您可以一次进行一次计算,然后才能从矩阵中获取结果,因此您将具有性能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("%dn", M(6,3));
printf("%dn", MNR(6,3));
}
,除非您知道序列的n-th((m,n) - th)元素的n-th公式,最简单的方法是使用堆栈模拟递归。
代码应如下:
#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;
}
此函数慢的主要原因是因为它具有指数复杂性,并且不断重新计算相同的成员。一种可能的治疗方法是回忆模式(在此处使用C 中的示例用来解释)。这个想法是将每个结果存储在具有快速访问(例如数组)的结构中,并且每次需要它,都会检索已预先计算的结果。当然,这种方法受您的内存大小的限制,因此它不能用于极大的数字...
在您的情况下,我们可以做类似的事情(保持递归但记忆结果):
#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;
}
关于时间复杂性,C 地图是树地图,因此搜索n*log(n)的顺序,其中n是地图的大小(已经计算的结果数)。也有C 的哈希地图,这是STL的一部分,但不是标准库的一部分,如SO所述。哈希地图承诺持续的搜索时间(虽然未指定常数的值:)),因此您也可以尝试一下。
您可以使用一个当数组来计算。小理论,
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
现在,如何计算此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];
}
//或一些优化
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];
}
- 是否应避免从非常量迭代器转换为常量迭代器?
- 迭代字符串集时没有可行的转换
- 为什么我的模板化函数需要从一个迭代器转换到另一个迭代器?
- 如何将 UTF-8 文本从文件转换为某个可以迭代的容器,并检查每个符号是否为C++字母数字?
- C++ 如何为自己的迭代器类从迭代器转换为const_iterator?
- C++如何乘以包含 std::variant 元素的向量的迭代器?正在执行迭代器类型的转换?
- 在插入容器之前转换输出迭代器
- 从基于迭代器的for循环转换后,如何在map::find()中调用方法
- C++将向量迭代器转换为索引
- 如何转换不同类型的迭代器
- 从迭代器转换为变量的类型.(C++11 模板)
- 转换迭代器和const_iterators
- 如何将值转换为迭代器
- 我的代码在作为参数传入 .begin() 时不起作用,但在我将 .begin() 转换为迭代器后工作
- 为什么在此代码中隐式转换为常量迭代器失败?
- 返回迭代器以提升适配器转换的容器
- 提高迭代器转换const_iterator
- 将多个非原始递归调用转换为迭代解决方案
- 我通过迭代加法将二进制数转换为十进制并检查单个字符(请参阅代码)的方法有什么问题?
- 将 C# 中的"from ... in "迭代转换为C++ (Qt)