'Convert c++ function from recursive to iterations with stack
I'm trying to convert this function from recursive to iterations with stack but I can't figure out how and I keep failing
int F(int n)
{
if (n <= 1) return 1;
int a = n + F(n - 1);
cout << a << endl;
int b = n * F(n / 2);
int c = n - 2 - (a + b) % 2;
int d = F(c);
return a + b + d;
}
I tried to debug the code and break it down but luck was not on my side
edit: these are the requirements
- You are not allowed to use any built-in functions except those from:
<cstdlib>,<cstdio>,<cstring>,<iostream>and<stack>. - You are not allowed to use
string,vector, or anything from STL libraries exceptstack.
Moreover, I attempted to make multiple stack for each variable to store the results then substitute the answer but am still working on it.
Solution 1:[1]
Let's look at the single parts of the recursion:
We have f(n-1), f(n/2) and f(n-2-[0 or 1], no matter how big a or b might ever get. All these recursive calls fall back to a lower value.
First few values:
f(n) = 1; // n <= 1
f(2) = (2 + f(1)) + (2 * f(1)) + f(-1) // (c = 2 - 2 - 5 % 2)
= 6
f(3) = (3 + f(2)) + (3 * f(1)) + f(1) // (c = 3 - 2 - 12 % 2)
= 13
f(4) = (4 + f(3)) + (4 * f(2)) + f(1) // (c = 4 - 2 - 41 % 2)
= 42
f(5) = (5 + f(4)) + (5 * f(2)) + f(2) // (c = 5 - 2 - 77 % 2)
= 83
Obviously we can calculate a new value based on old ones – and if we calculate these first, we can simply look them up – apart from n == 2 where we'd get a negative lookup index. So we might initialise a std::vector with f(0), f(1) and f(2) (i.e. 1, 1, 6) and then iterate from 3 onwards until n calculating new values based upon the lookups of old ones:
if n <= 1:
return 1;
std::vector v({1, 1, 6});
if n >= v.size():
v.reserve(n + 1); // avoid unnecessary re-allocations
iterate i from v.size() up to n inclusive:
v.push_back(calculate, instead recursive calls look up in vector!);
return v[n];
Optimisation opportunity: If you retain results from previous calculations you don't need to re-calculate the values again and again (for the price of constantly instead of temporarily consuming quite a bit of memory!); all you have to do for is making the vector static:
static std::vector v({1, 1, 6});
// ^^^^^^
Edit – according to the edits of the question (referring to version 4):
As you are not allowed to use std::vector as proposed above instead allocate an array:
auto v = new unsigned int[std::max(3, n + 1)] { 1, 1, 6};
// I personally prefer unsigned int as negative values aren't possible anyway...
// calculate as with the vector
auto result = v[n];
delete[] v;
return result;
Keeping old values for future calls still is possible, but more complicated; you need to remember how large your array is and if n is greater than the size re-allocate a new array, copy values from old one to and delete the latter.
This approach keeps the requirements of the task as using std::stack is not explicitly requested... If that gets enforced then the algorithm won't change – solely the lookup gets pretty ugly; you need in addition to your main stack a temporary one to be able to backup the elements on top of those you want to lookup up:
// lookup the three values in DESCENDING order, each one
// as follows:
while(stack.size() > lookupIndex)
{
backup.push(stack.top());
stack.pop();
}
// now top elements have been moved away from main stack and
// backed up; the element to be looked up is moved, too;
// for illustration: consider lookupIndex == 0; what would be
// the main stack's size after popping the surplus elements???
lookupValue = backup().top();
// now as you have looked up all three values move the elements
// in the backup stack back to the main stack:
while(!backup.empty()) { /* analogously to above */ }
You can spare moving back if you are calculating the final value for n – unless you retain the main stack for future calls analogously to the static vector above (make it static analogously...).
Final note: I think more than anything else you can learn from this example how much additional effort – in coding and in runtime – you will load upon your shoulders if you chose a bad data structure compared to having chosen a suitable one...
Solution 2:[2]
Consider that
F(n) = 1 for all n <= 1, especially
F(0) = 1 and F(1) = 1
This is basically all you need to get the solution with a loop:
int F2(int n) {
std::vector<int> F{1,1};
for (int i=2;i <= n; ++i) {
int a = i + F[i-1];
int b = i * F[i/2];
int x = i-2-(a+b)%2; // might be negative
int d = x>0 ? F[x] : 1;
F.push_back(a+b+d);
}
return F.back();
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | 463035818_is_not_a_number |
