There is an issue with the recursive definition of the fibonacci sequence when it comes to efficiency. It is defined as follows:
private fib(int n) {
if(n < 2) return n;
else return fib(n - 1) + fib(n-2);
}
Suppose we call fib(5). This makes 1 call to fib(4) , two calls to fib(3), three calls to fib(2), five calls to fib(1) and three calls to fib(0).
In his book
Programming Abstractions in Java by Eric Roberts
Roberts mentions that we can resolve this efficiency issue by realizing that the fibonacci sequence is just a special case of the additiveSequence(int n, int t0, int t1) method. Basically, the Fibonacci sequence is just an additive sequence that strictly begins with 0 and 1. There are an infinite number of sequences that match the recurrence relation expressed by Fibonacci.
The author resolves the efficiency issue as follows:
private int fib(int n) {
return additiveSequence(n, 0, 1);
}
So my questions is, by making the fib sequence a wrapper for the more general additiveSequence method, are we really improving efficiency ? Wouldn't the implementation of additiveSequence have the same exact "problem" in terms of efficiency that fib had, given that it does follow the same exact reccurence relation ?
Here's an example implementation of an additive sequence calculation, where ti = ti-1 + ti-2:
int additiveSequence(int n, int t0, int t1) {
if(n==0) return t0;
if(n==1) return t1;
return additiveSequence(n-1, t1, t0+t1);
}
This method returns the n-th value in the series. Work through some examples and you should be able to convince yourself that each ti will be calculated only once. Compare that with your naively implemented fib method and you can see why this approach is much faster.
The Fibonacci series is this kind of additive sequence, with the starting conditions t0 = 0 and t1 = 1. There's nothing particularly special about it, other than the fact that the obvious way to code it is a poor one. The author's point, presumably, is that implementation makes a huge difference in processing time. It does not appear to be clearly explained, however.
Related
Here is a recursive function. Which traverses a map of strings(multimap<string, string> graph). Checks the itr -> second (s_tmp) if the s_tmp is equal to the desired string(Exp), prints it (itr -> first) and the function is executed for that itr -> first again.
string findOriginalExp(string Exp){
cout<<"*****findOriginalExp Function*****"<<endl;
string str;
if(graph.empty()){
str ="map is empty";
}else{
for(auto itr=graph.begin();itr!=graph.end();itr++){
string s_tmp = itr->second;
string f_tmp = itr->first;
string nll = "null";
//s_tmp.compare(Exp) == 0
if(s_tmp == Exp){
if(f_tmp.compare(nll) == 0){
cout<< Exp <<" :is original experience.";
return Exp;
}else{
return findOriginalExp(itr->first);
}
}else{
str="No element is equal to Exp.";
}
}
}
return str;
}
There are no rules for stopping and it seems to be completely random. How is the time complexity of this function calculated?
I am not going to analyse your function but instead try to answer in a more general way. It seems like you are looking for an simple expression such as O(n) or O(n^2) for the complexity for your function. However, not always complexity is that simple to estimate.
In your case it strongly depends on what are the contents of graph and what the user passes as parameter.
As an analogy consider this function:
int foo(int x){
if (x == 0) return x;
if (x == 42) return foo(42);
if (x > 0) return foo(x-1);
return foo(x/2);
}
In the worst case it never returns to the caller. If we ignore x >= 42 then worst case complexity is O(n). This alone isn't that useful as information for the user. What I really need to know as user is:
Don't ever call it with x >= 42.
O(1) if x==0
O(x) if x>0
O(ln(x)) if x < 0
Now try to make similar considerations for your function. The easy case is when Exp is not in graph, in that case there is no recursion. I am almost sure that for the "right" input your function can be made to never return. Find out what cases those are and document them. In between you have cases that return after a finite number of steps. If you have no clue at all how to get your hands on them analytically you can always setup a benchmark and measure. Measuring the runtime for input sizes 10,50, 100,1000.. should be sufficient to distinguish between linear, quadratic and logarithmic dependence.
PS: Just a tip: Don't forget what the code is actually supposed to do and what time complexity is needed to solve that problem (often it is easier to discuss that in an abstract way rather than diving too deep into code). In the silly example above the whole function can be replaced by its equivalent int foo(int){ return 0; } which obviously has constant complexity and does not need to be any more complex than that.
This function takes a directed graph and a vertex in that graph and chases edges going into it backwards to find a vertex with no edge pointing into it. The operation of finding the vertex "behind" any given vertex takes O(n) string comparisons in n the number of k/v pairs in the graph (this is the for loop). It does this m times, where m is the length of the path it must follow (which it does through the recursion). Therefore, it has time complexity O(m * n) string comparisons in n the number of k/v pairs and m the length of the path.
Note that there's generally no such thing as "the" time complexity for just some function you see written in code. You have to define what variables you want to describe the time in terms of, and also the operations with which you want to measure the time. E.g. if we want to write this purely in terms of n the number of k/v pairs, you run into a problem, because if the graph contains a suitably placed cycle, the function doesn't terminate! If you further constrain the graph to be acyclic, then the maximum length of any path is constrained by m < n, and then you can also get that this function does O(n^2) string comparisons for an acyclic graph with n edges.
You should approximate the control flow of the recursive calling by using a recurrence relation. It's been like 30 years since I took college classes in Discrete Math, but generally you do like pseuocode, just enough to see how many calls there are. In some cases just counting how many are on the longest condition on the right hand side is useful, but you generally need to plug one expansion back in and from that derive a polynomial or power relationship.
Suppose I am solving a dynamic programming problem recursively (top down). For example, a recursive solution to the longest common subsequence problem:
LCS(S,n,T,m)
{
if (n==0 || m==0) return 0;
if (S[n] == T[m]) result = 1 + LCS(S,n-1,T,m-1);
else result = max( LCS(S,n-1,T,m), LCS(S,n,T,m-1) );
return result;
}
Often in such a DP problem at some point we have to take the max of some expressions, representing returns to different choices we can make. In the above case we have the max of two simple expressions, but in worse cases it can be the max of three or four quite complicated expressions involving long function calls. In such situations, I am often tempted to give these complicated expressions their own variable names, to make the code more readable. In the above case that would mean I would write
LCS(S,n,T,m)
{
if (n==0 || m==0) return 0;
if (S[n] == T[m]) result = 1 + LCS(S,n-1,T,m-1);
else
a = LCS(S,n-1,T,m);
b = LCS(S, n, T, m-1);
result = max(a, b);
return result;
}
(In this simplified case a and b are not complicated, but in other cases they are, and there may be even more arguments to the max function, so this could really help it be more understandable.)
My Question: Is this a terrible idea? As I understand it, I'm adding a variable to each layer of the call stack, and I'm thinking that could be wasteful. But on the other hand, at each layer it has to calculate the temporary variable LCS(S,n,T,m) anyway (I'm thinking in terms of C++, say), and as far as I know, there might be not much difference in cost between the two ways.
If this is a terrible idea, is there a more efficient way to break up a complicated recursive function call to make it more readable?
C++ has the "As-If" rule, which states that a compiler can do whatever it wants so long as the observable effects are indistinguishable from what is defined by the standard to happen. In this case, it's trivial to prove both fragments have the same meaning, and a compiler will likely emit identical instructions for both.
Note: You aren't doing dynamic programming here, as you don't memoise parameter / result pairs.
In the book "Think like a programmer", the following recursive function is said to be "highly inefficient" and I can't figure out why (the book does not explain). It doesn't seem like there are any unnecessary calculations being done. Is it because of the overhead of calling so many functions (well the same function multiple times) and thus setting up environments for each call to the function?
int factorial(int n) {
if (n == 1) return 1;
else return n * factorial(n-1);
}
It is inefficient in two ways, and you hit one of them:
It is recursive, instead of iterative. This will be highly inefficient if tail-call optimization is not enabled. (To learn more about tail-call optimization, look here.) It could have been done like this:
int factorial(int n)
{
int result = 1;
while (n > 0)
{
result *= n;
n--;
}
return result;
}
or, alternatively, with a for loop.
However, as noted in comments above, it doesn't really matter how efficient it is if an int can't even hold the result. It really should be longs, long longs, or even big-ints.
The second inefficiency is simply not having an efficient algorithm. This list of factorial algorithms shows some more efficient ways of computing the factorial by decreasing the number of numerical operations.
There is significant function call overhead in C when not using a compiler that implements tail call optimization.
Function call overhead is the extra time and memory necessary for a computer to properly set up a function call.
Tail call optimization is a method of turning recursive functions like the one given into a loop.
I think the book writer may want to tell readers to not abuse recursion. For this function you could just use:
int factorial(int n) {
int res = 1;
for (i = 1; i <= n; i++) {
res = res * i;
}
return res;
}
Recursion is slower as well as memory eater in terms of Memory Stack.It is a time taking work to push info onto the stack and again to pop it .The main advantage of recursion is that it makes the algorithm a little easier to understand or more "elegant".
For finding the factorial we can use For loop that will be good in terms of memory as well as Time Complexity.
int num=4;
int fact = 1;
for (;num>1;num--)
{
fact = fact*num;
}
//display fact
How would you find a T(n) run-time (not the big O run time) for a function that has two inputs? Do you just consider the a input your 'n'?
int h(int a, int b) {
if (a > 0) {
return h(a-1, a+b);
}
else {
return 0;
}
}
In this case we just need to consider a since the length of this algorithm isn't dependent on b.
In other words since we can pass in 20000 or -2 for b and not impact our time in the slightest (ignoring the actual time of adding a+b) we shouldn't have to consider b in our calculations.
In a more general case, if the input did depend on a and b we would simply account for this in our time complexity function. In other words it would be T(a, b) not just T(a).
as this function recurs only on a and a is decreasing by 1 in each step, it would give linear complexity. So answer would be T(a).
Given that for each and every (a,b)-pair the function value is zero - the recursion will always end in the else-branch - the compiler may be smart enough to reduce the code effectively to "return 0" for the whole body and leave all the if/else and recursion stuff out, resulting in O(1) complexity and corresponding run time.
Guys I'm working on class called LINT (large int) for learning purposes, and everything went ok till know. I'm stuck on implementing operator/(const LINT&). The problem here is that in when I want to divide LINT by LINT I'm getting into recursive fnc invocation i.e:
//unfinished
LINT_rep LINT_rep::divide_(const LINT_rep& bottom)const
{
typedef LINT_rep::Iterator iter;
iter topBeg = begin();
iter topEnd = end();
iter bottomBeg = bottom.begin();
iter bottomEnd = bottom.end();
LINT_rep topTmp;//for storing smallest number (dividend) which can be used to divide by divisor
while (topBeg != topEnd)
{
topTmp.insert_(*topBeg);//Number not large enough add another digit
if (topTmp >= bottom)
{//ok number >= we can divide
LINT_rep topShelf = topTmp / bottom;//HERE I'M RUNNING INTO TROUBLE
}
else
{
}
++topBeg;
}
return LINT_rep("-1");//DUMMY
}
What I'm trying to do is to implement this as if I would divide those numbers by hand, so for example having for a dividend 1589 and for divisor 27 I would go like so:
check if first digit is >= divisor and if so divide
if not add to the first digit another digit and check if a > b
At some point it will be bigger (in simplified scenario) and if so I have to divide but in this case I'm running into recursive call and I have no idea how to break it.
One note: as a tmp I have to use LINT instead of int for example because those numbers my not fit into int.
So generally what I'm asking for is there any other way to do division? Or maybe there is false logic in my thinking (quite possible).
Thank you.
When doing your part (1) you can't divide; you have to repeatedly subtract, or guess to subtract a multiple, just like when you do it by hand. You can 'guess' more effectively by setting upper and lower bounds for the multiple required and doing a binary-chop through the range.
I've done a similar thing myself; it's a handy exercise to practice operator overloading. I can supply a snippet of code if you like, although it uses arrays and half-baked exceptions so I hesitate to offer it up before the expert readers of this site.
First, please don't work on such a class. Use CGAL's big int, and there was some boost bigint submission I think, also, there're about three or four other popular implementations.
Second, the division algorithm is described here: http://en.wikipedia.org/wiki/Long_division
[EDIT] Correct way to do it:
Digit k of the result (C):
if first digit (from left) of A, call it A[nA-1] is smaller than B[nB-1], write zero into C[k]. k-- (move to next digit).
Otherwise, you seek maximum digit C[k] so that C[k]*B*10^k <= A. That is done in a loop. Actually, the previous sentence is a private case of this one. But it is not yet finished. You do A-=C[k]*B*10^k (the substracted part was zero otherwise). Only then,
k-- (next digit). Loop until k==0.
No need for recursion. Just two nested loops.
One loop for k (digit of the result), one loop for finding every digit, one loop (near it) for substracting (the -= operator).