Recurrence relation for given algorithm? - algorithm

int print4Subtree(struct Node *root) {
if (root == NULL)
return 0;
int l = print4Subtree(root->left);
int r = print4Subtree(root->right);
if ((l + r + 1) == 4)
printf("%d ", root->data);
return (l + r + 1); }
This algorithm/code finds number of subtrees having exactly 4 nodes in binary tree , it's works in bottom-up manner .
I know the time complexity of this code would be O(n) , and space complexity is O(log n) , since it's using recursion.
What will be recurrence relation for the code ?
I try to draw T(n) = 2T(n-1)+1 , which is obviously wrong !

You can only talk about recurrence relations in terms of n alone in cases where you know more about the structure of the tree, for instance:
Case 1: Every node has only one child meaning
T(n) = T(0) + T(n-1) + k.
Case 2: Subtrees at any level are balanced so that
T(n) = 2 T((n-1)/2) + k.
Both of these will result in O(n), but these two cases are only a very select minority of possible trees. For a more universal approach you have to use a formula like T(n) = T(a) + T(b), where a and b are an arbitrary division into sub-problems resulting from the structure of your tree. You can still establish results from this kind of formula using strong induction.
The following is the exact formula and approach I would use:
T(n) = nk + mnc, where mn ≤ n + 1. (Note: I am using k for overhead of recursive steps and c for overhead of base/null steps).
Base case (n=0):
For a null node T(0) = c so T(n) = kn + mnc ,
where mn = 1 ≤ n+1 = 1.
Inductive step (T(x) = xk + mxc for all x < n):
The sub_tree of size n has two sub-trees of sizes a and b (a or b may be 0) such that n = a + b + 1.
T(n) = T(a) + T(b) + k = ak + mac + bk + mbc + k = (a+b+1)k + (ma+mb)c = nk + mnc ,
where mn = ma + mb ≤ a + 1 + b + 1 = n + 1.
The reason for using mn is merely a formality to make the proof smoother, as the exact number of null cases is what is actually affected by the structure of tree (in the former case 2, it is log n). So T(n) is at best O(n) because of the nk term, and can be no worst than O(n) because of the bound on mnc.

Related

Analyzing Worst Case Performance of Quicksort by Substitution Method

I am trying to solve the reccurence of the quicksort algorithm by the substitution method:
I can not find any way to proof that this will lead to . What further steps do I have to make to make this work?
The worst case of quicksort is when you choose a pivot element which is the minimum or maximum element from the array, so that all remaining elements go to one side of the partition, and the other side of the partition is empty. In this case, the non-empty partition has a size of (n - 1), and it takes linear time (kn for some constant k > 0) to do the partitioning itself, so the recurrence relation is
T(n) = T(n - 1) + T(0) + kn
If we guess that T(n) = an² + bn + c for some constants a, b, c, then we can substitute:
an² + bn + c = [ a(n - 1)² + b(n - 1) + c ] + [ c ] + kn
where the two square-bracketed terms are T(n - 1) and T(0) respectively. By expanding the brackets and equating coefficients, we get
an² = an²
bn = -2an + bn + kn
c = a - b + 2c
It follows that there is a family of solutions, parameterised by c = T(0), where a = k/2 and b = k/2 + c. This family of solutions can be written exactly as
T(n) = (k/2) n² + (k/2 + c) n + c
which is not just O(n²), but Ө(n²), meaning the running time is a quadratic function, not merely bounded above by a quadratic function. Note that the actual value of c doesn't change the asymptotic behaviour of the function, so long as k > 0 (i.e. the partitioning step does take a positive amount of time).
I have found an answer to my question, the continuation of the previous equation is,
This is true if

Running Time of Randomized Binary Search

Consider the following silly randomized variant of binary search. You are given a sorted array
A of n integers and the integer v that you are searching for is chosen uniformly at random from A.
Then, instead of comparing v with the value in the middle of the array, the randomized binary search
variant chooses a random number r from 1 to n and it compares v with A[r]. Depending on whether
v is larger or smaller, this process is repeated recursively on the left sub-array or the right sub-array,
until the location of v is found. Prove a tight bound on the expected running time of this algorithm.
Here is what I got for the T(n)
T(n) = T(n-r) + T(r) + Θ(1)
However, I have no clue how to get a tight bound.
Your formulation of T(n) is not completely correct. Actually,
Lets try to look over all the cases. When we reduce the problem size by partitioning the array across any random point, the reduced sub-problem will have any size from 1 to n with uniform probability. Hence with probability 1/n, search space becomes r. So expected running time becomes
T(n) = sum ( T(r)*Pr(search space becomes r) ) + O(1) = sum ( T(r) )/n + O(1)
Which gives,
T(n) = average(T(r)) + O(1)
Let expected time complexity of random binary sort be T(n).
T(n) = [ T(1)+T(2)+...+T(n)]/n + 1
n*T(n) = T(1)+T(2)+...+T(n) + n
(n-1)*T(n-1) = T(1)+T(2)+...+T(n-1) + n-1 [substituiting n by n-1]
n*T(n) - (n-1)*T(n-1) = T(n) + 1
(n-1)*T(n) - (n-1)*T(n-1) = 1
(n-1)*T(n) = (n-1)*T(n-1) + 1
T(n) = 1/(n-1) + T(n-1)
T(n) = 1/(n-1) + 1/(n-2) + T(n-2) [ T(n-1) = T(n-2) + 1/(n-2) ]
...
T(n) = 1 + 1/2 + 1/3 + ... + 1/(n-1) = H(n-1) < H(n) = O(log n)
[ H(n) = reciprocal sum of first n natural numbers ]
so, T(n) = O(log n)
Harmonic number
bound of H(n)

Proving this recursive Fibonacci implementation runs in time O(2^n)?

I'm having difficulty proving that the 'bad' version of fibonacci is O(2^n).
Ie.
Given the function
int fib(int x)
{
if ( x == 1 || x == 2 )
{
return 1;
}
else
{
return ( f( x - 1 ) + f( x - 2) );
}
}
Can I get help for the proof of this being O(2^n).
Let's start off by writing a recurrence relation for the runtime:
T(1) = 1
T(2) = 1
T(n+2) = T(n) + T(n + 1) + 1
Now, let's take a guess that
T(n) ≤ 2n
If we try to prove this by induction, the base cases check out:
T(1) = 1 ≤ 2 = 21
T(2) = 1 ≤ 4 = 22
Then, in the inductive step, we see this:
T(n + 2) = T(n) + T(n + 1) + 1
≤ 2n + 2n+1 + 1
< 2n+1 + 2n+1
= 2n+2
Therefore, by induction, we can conclude that T(n) ≤ 2n for any n, and therefore T(n) = O(2n).
With a more precise analysis, you can prove that T(n) = 2Fn - 1, where Fn is the nth Fibonacci number. This proves, more accurately, that T(n) = Θ(φn), where φ is the Golden Ratio, which is approximately 1.61. Note that φn = o(2n) (using little-o notation), so this is a much better bound.
Hope this helps!
Try manually doing a few test cases like f(5) and take note of how many times the method f() is called.
A fat hint would be to notice that every time the method f() is called (except for x is 1 or 2), f() is called twice. Each of those call f() two more times each, and so on...
There's actually a pretty simple proof that the total number of calls to the f is going to be 2Fib(n)-1, where Fib(n) is the n'th Fibonacci number. It goes like this:
The set of calls to f form a binary tree, where each call is either a leaf (for x=1 or x=2) or else the call spawns two child calls (for x>2).
Each leaf contributes exactly 1 to the total returned by the original call, therefore there are Fib(n) total leaves.
The total number of internal nodes in any binary tree is equal to L-1, where L is the number of leaves, so the total number of nodes in this tree is 2L-1.
This shows that the running time (measured in terms of total calls to f) is
T(n)=2Fib(n)-1=O(Fib(n))
and since Fib(n)=Θ(φ^n), where φ is the golden ratio
Φ=(1+sqrt{5})/2 = 1.618...
this proves that T(n) = Θ(1.618...^n) = O(n).
Using the Recursion Tree Method :
T(n)
↙ ↘
n-1 n – 2
↙ ↘ ↙ ↘
N – 2 n – 3 n – 3 n - 4
Each tree level is considered as a call for fib(x - 1) fib(x - 2) if you complete the recursion tree on this manner you will stop when x = 1 or x = 2 (base case) .... this tree shows only three levels of the recursion tree . To solve this tree you need these important informations : 1- height of the tree. 2-how much work is done at each level .
The height of this tree is 2^n and the work at each level is O(1) then the Order of this recurrence is Height * Work at each level = 2^n * 1 = O(2^n)

How to solve: T(n) = T(n/2) + T(n/4) + T(n/8) + (n)

I know how to do recurrence relations for algorithms that only call itself once, but I'm not sure how to do something that calls itself multiple times in one occurrence.
For example:
T(n) = T(n/2) + T(n/4) + T(n/8) + (n)
Use Recursion Tree. See the last example of Recursion tree at CLRS "Intro to Algorithm".
T(n) = T(n/2) + T(n/4) + T(n/8) + n. The root will be n(cost) & divided into 3 recursions. So the recursion tree looks like as follows:
T(n) = n = n
T(n/2)T(n/4)T(n/8) (n/2) (n/4) (n/8)
T(n/4)T(n/8)T(n/16) T(n/8)T(n/16)T(n/32) T(n/16)T(n/32)T(n/64)
n---------------------------------> n
(n/2) (n/4) (n/8)--------------> (7/8)n
n/4 n/8 n/16 n/8 n/16 n/32 n/16 n/32 n/64)--------> (49/64)n
...
Longest path: the leftmost left branch = n -> n/2 -> n/4 -> ... -> 1
Shortest branch: the rightmost right branch = n -> n/8 -> n->64 -> ... -> 1
The number of leaves (l): 3^log_8(n) < l < 3^log_2(n) => n^0.5 < l < n^1.585
Look at the tree - upto log_8(n) levels the tree is full, and then as we go down, more & more internal nodes are absent. By this theory we can give the bound,
T(n) = Big-Oh (Summation j=0 to log_2(n)-1 (7/8)^j n) = ... => T(n) = O(n).
T(n) = Big-Omega (Summation j=0 to log_8(n)-1 (7/8)^j n) = ... => T(n) = Big-Omega(n).
Therefore, T(n) = Theta(n).
Here the points are:
T(n/2) path has the highest length...
This must not be a complete ternary tree ... height = log base 2 of n & # of leaves must be less than n ...
Hope, likely this way u can solve the prob.
See the Image for a better explanation-
Height of Tree: We took log(n)(base 2) because n/2 make the tree longer in comparison to n/4, and n/8. And our GP series will go till k=logn(base).
There are two ways of solving this. One is unrolling recursion and finding similarities which can require inventiveness and can be really hard. Another way is to use Akra-Bazzi method.
In this case g(x) = n, a1 = a2 = a3 = 1 and b1 = 1/2, b2 = 1/4, b3 = 1/8. Solving the equation
which is 1/2^p + 1/4^p + 1/8^p = 1 you get p = 0.87915. Solving the integral you will get , which means that the complexity is: O(n)
Just like coding the Fibonacci Sequence (the hard way) as an example, you would simply type something along the lines of:
long fib(long n){
if(n <= 1) return n;
else return fib(n-1) + fib(n-2);
}
Or, better yet, memoize it using a global variable to make it much quicker. Once again, with the Fibonacci Sequence:
static ArrayList<Long>fib_global = new ArrayList(1000);
//delcare a global variable that can be appended to
long fib(long n){
if(n >= fib_global.length)fib_global.add(fib(n-1) + fib(n-2));
return fib_global.get(n);
}
The code will only execute one of these calls at a time, and most likely in the left-to-right order you typed them in, making it so that you only don't really need to worry about the amount of times you needed to call something.
As CLRS has said, T(n) can be replaced by cn by mathematical induction. This inductive assumption works for the number below n. As mentioned above, what we need to prove is that the parameter value is n. Therefore, as follows:
assume: T(n) <= cn for the number below n;
conclude:
T(n) = T(n/2) + T(n/4) + T(n/8) + n
<= c/2*n + c/4*n + c/8*n + n
= (7/8*c + 1) * n
<= cn (when c >= 8)
that's all.

Can someone help solve this recurrence relation? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
T(n) = 2T(n/2) + 0(1)
T(n) = T(sqrt(n)) + 0(1)
In the first one I use substitution method for n, logn, etc; all gave me wrong answers.
Recurrence trees: I don't know if I can apply as the root will be a constant.
Can some one help?
Let's look at the first one. First of all, you need to know T(base case). You mentioned that it's a constant, but when you do the problem it's important that you write it down. Usually it's something like T(1) = 1. I'll use that, but you can generalize to whatever it is.
Next, find out how many times you recur (that is, the height of the recursion tree). n is your problem size, so how many times can we repeatedly divide n by 2? Mathematically speaking, what's i when n/(2^i) = 1? Figure it out, hold onto it for later.
Next, do a few substitutions, until you start to notice a pattern.
T(n) = 2(2(2T(n/2*2*2) + θ(1)) + θ(1)) + θ(1)
Ok, the pattern is that we multiply T() by 2 a bunch of times, and divide n by 2 a bunch of times. How many times? i times.
T(n) = (2^i)*T(n/(2^i)) + ...
For the big-θ terms at the end, we use a cute trick. Look above where we have a few substitutions, and ignore the T() part. We want the sum of the θ terms. Notice that they add up to (1 + 2 + 4 + ... + 2^i) * θ(1). Can you find a closed form for 1 + 2 + 4 + ... + 2^i? I'll give you that one; it's (2^i - 1). It's a good one to just memorize, but here's how you'd figure it out.
Anyway, all in all we get
T(n) = (2^i) * T(n/(2^i)) + (2^i - 1) * θ(1)
If you solved for i earlier, then you know that i = log_2(n). Plug that in, do some algebra, and you get down to
T(n) = n*T(1) + (n - 1)*θ(1). T(1) = 1. So T(n) = n + (n - 1)*θ(1). Which is n times a constant, plus a constant, plus n. We drop lower order terms and constants, so it's θ(n).
Prasoon Saurav is right about using the master method, but it's important that you know what the recurrence relation is saying. The things to ask are, how much work do I do at each step, and what is the number of steps for an input of size n?
Use Master Theorem to solve such recurrence relations.
Let a be an integer greater than or equal to 1 and b be a real number greater than
1. Let c be a positive real number and
d a nonnegative real number. Given a recurrence of the form
T (n) = a T(n/b) + nc .. if n > 1
T(n) = d .. if n = 1
then for n a power of b,
if logb a < c, T (n) = Θ(nc),
if logb a = c, T (n) = Θ(nc log n),
if logb a > c, T (n) = Θ(nlogb a).
1) T(n) = 2T(n/2) + 0(1)
In this case
a = b = 2;
logb a = 1; c = 0 (since nc =1 => c= 0)
So Case (3) is applicable. So T(n) = Θ(n) :)
2) T(n) = T(sqrt(n)) + 0(1)
Let m = log2 n;
=> T(2m) = T( 2m / 2 ) + 0(1)
Now renaming K(m) = T(2m) => K(m) = K(m/2) + 0(1)
Apply Case (2).
For part 1, you can use Master Theorem as #Prasoon Saurav suggested.
For part 2, just expand the recurrence:
T(n) = T(n ^ 1/2) + O(1) // sqrt(n) = n ^ 1/2
= T(n ^ 1/4) + O(1) + O(1) // sqrt(sqrt(n)) = n ^ 1/4
etc.
The series will continue to k terms until n ^ 1/(2^k) <= 1, i.e. 2^k = log n or k = log log n. That gives T(n) = k * O(1) = O(log log n).
Let's look at the first recurrence, T(n) = 2T(n/2) + 1. The n/2 is our clue here: each nested term's parameter is half that of its parent. Therefore, if we start with n = 2^k then we will have k terms in our expansion, each adding 1 to the total, before we hit our base case, T(0). Hence, assuming T(0) = 1, we can say T(2^k) = k + 1. Now, since n = 2^k we must have k = log_2(n). Therefore T(n) = log_2(n) + 1.
We can apply the same trick to your second recurrence, T(n) = T(n^0.5) + 1. If we start with n = 2^2^k we will have k terms in our expansion, each adding 1 to the total. Assuming T(0) = 1, we must have T(2^2^k) = k + 1. Since n = 2^2^k we must have k = log_2(log_2(n)), hence T(n) = log_2(log_2(n)) + 1.
Recurrence relations and recursive functions as well should be solved by starting at f(1). In case 1, T(1) = 1; T(2) = 3; T(4) = 7; T(8) = 15; It's clear that T(n) = 2 * n -1, which in O notation is O(n).
In second case T(1) = 1; T(2) = 2; T(4) = 3; T(16) = 4; T(256) = 5; T(256 * 256) =6; It will take little time to find out that T(n) = log(log(n)) + 1 where log is in base 2. Clearly this is O(log(log(n)) relation.
Most of the time the best way to deal with recurrence is to draw the recurrence tree and carefully handle the base case.
However here I will give you slight hint to solve using substitution method.
In recurrence first try substitution n = 2^k
In recurrence second try substitution n = 2^2^k

Resources