Calculating the complexity of this function - c

This is the function:
void f(int n)
{
for(int i=0; i<n; ++i)
for(int j=0; j<i; ++j)
for(int k=i*j; k>0; k/=2)
printf("~");
}
In my opinion, the calculation of the time complexity would end up to be something like this:
log((n-1)(n-2))+log((n-1)(n-3))+...+log(n-1)+log((n-2)(n-3))+...+log(n-2)+...log(2)
So, I get a time complexity of nlog(n!) (because loga+logb=log(a*b) and because n-1,n-2,n-3,... each appears n-1 times in total.
However, the correct answer is n^2*logn, and I have no idea where my mistake is. Could anyone here help?
Thanks a lot!

log(n!) can be approximated as (n+1/2)log(n) - n + constant (see https://math.stackexchange.com/questions/138194/approximating-log-of-factorial)
So the complexity is n*n*log(n) as expected.
Simpler: compute the complexity loop by loop independently and multiply them.
First 2 outer loops: trivial: n each, which makes n^2
Inner loop: has a log(n**2) complexity which is the same as log(n)
So n^2log(n) is the correct answer.

The Complexity is O(N*N*LOG_2(N^2)).
The first and the second loop both have O(N) and the last loop in k has logarithmic grow.
LOG_2(N^2) = 2*LOG_2(N) and
O(N*M)=O(N)*O(M).
O(constant)=1.
So for the grow of the last loop you can write also O(LOG_2(N^2))=O(LOG(N)).

Related

Determining the time complexity of this code?

I think the time complexity of this code will be O(n^2) but I am not sure so if someone can explain what will be the time complexity of this code it would be really helpful
int func2()
{
int i, j, k = 0;
scanf("%d", &n);
for (i = 1; i < n; i++)
{
i -= 1;
i *= 2;
k = k + i;
for (j = 1; j < n; j++);
}
}
It looks like an infinite loop to me, so the time complexity is O(infinity).
On the first iteration of the outer loop, i -= 1 will set i to 0. Multiplying by 2 leaves it still 0.
The loop iteration i++ will then increment i to 1, and the next iteration will repeat the above computations.
I am a beginner on time complexity but these are my views:-
The outer for loop is in the condition of an infinite loop as on the first iteration of the outer loop, execution starts with i=1.
On executing i -= 1 it will set i=0.
Executing i*=2, the value of i remains the same as 0.
On going in the increment phase, i is incremented and i=1.
So the same process occurs.
Thus the value of i remains the same causing it to run indefinitely.
Now, coming forward inside the outer for loop is a nested for (in the variable j) loop that is followed by a semicolon. This causes it to have a time complexity of O(1).
So the resultant overall time complexity can be expected to be O(infinity).
First, 'n' not declared here and input value is being assigned to it.
Second, technically, this code is an infinite loop (done ridiculously hard way) and for non-terminating, forever-running algorithms the time-complexity is 'Undefined' as by the principles of Algorithm Analysis, time-complexity is only computed for algorithms that perform a task with certainity to terminate.
In case if this would have been a terminating loop, time complexity of this function is O(n^2) would have been quadratic in nature due to nesting of for(;;) inside of another for(;;) with enclosed statements of O(1) - linear time complexity. The higher order complexity ( O(n^2) ) supersedes.

How to check Big O notation of a sorting algorithm?

I don't know how to solve it's complexity and such. How to know if it is faster than other sorting algorithms?
I find difficulty finding it because I'm a little bit bad at math.
#include <stdio.h>
int func(int arr[])
{
int temp;
int numofarrays=9999;
for(int runtime=1; runtime<=numofarrays/2; runtime++)
{
for(int i=0; i<=numofarrays; i++)
{
if(arr[i] > arr[i+1])
{
temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
}
if(arr[numofarrays-i-1] > arr[numofarrays-i])
{
temp=arr[numofarrays-i-1];
arr[numofarrays-i-1]=arr[numofarrays-i];
arr[numofarrays-i]=temp;
}
}
}
for(int i=0; i<=9999; i++)
{
printf("%i\n",arr[i]);
}
}
int main()
{
int arr[10000];
for(int i=0; i<=9999; i++)
{
arr[i]=rand() % 10;
}
func(arr);
}
The big o notation is where the limit of steps of the code you write goes to infinity. Since the limit goes to infinity, we neglect the coefficients and look at the largest term.
for(int runtime=1; runtime<=numofarrays/2; runtime++)
{
for(int i=0; i<=numofarrays; i++)
{
Here, the largest term of the first loop is n, and the largest term of the second is n. But since loop 2 makes n turns for each turn of the first loop, we're multiplying n by n.
Result is O(n^2).
Here:
for(int runtime=1; runtime<=numofarrays/2; runtime++)
{
for(int i=0; i<=numofarrays; i++)
{
you have two nested for loops that both depends of the array size. So the complexity is O(N^2).
Further you ask:
How to know if it is faster than other sorting algorithms?
Well big-O does not directly tell you about execution time. For some values of N an O(N) implementation may be slower than an O(N^2) implementation.
Big-O tells you how the execution time increases as N increase. So you know that an O(N^2) will be slower than an O(N) when N gets above a apecific value but you can't know what that value is! It could be 1, 5, 10, 100, 1000, ...
Example:
The empirical approach is to time (t) your algorithm for a given input of n. Then do that experiment for larger and large n, say, 2^n for n = 0 to 20. Plot (2^n, t) on a graph. If you get a straight line, it's a linear algorithm. If you get something that grows faster, try graph ln(t) and see if you get a line, that would be an exponential algorithm, etc.
The analytical approach looks scary and sometimes math heavy, but it's doesn't really have to be. You decide what your expensive operation is, then you count how of many of those you do. Anything that runs in loops including recursive functions are the main candidates the run-time of that goes up as the loop runs more times:
Let's say we want count the number of swaps.
The inner loop swap numofarrays times which is O(n).
The outer loop runs numofarrays/2 times which is also O(n) as we drop the factor 1/2 as it's doesn't matter when n gets large.
This mean we do O(n) * O(n) = O(n^2) number of swaps.
Your print loop, is not doing any swaps so we consider them "free", but if determine that they are as expensive as swaps then we want to count those too. Your algorithm does numofarrays print operations which is O(n).
O(n^2) + O(n) is just O(n^2) as the larger O(n^2) dominates O(n) for sufficiently large n.

time complexities on while loop with condition of n*n

i=1;
while(i<n*n)
i=i+n;
from my lecturer provided answer:
Big-O notation was O(n) instead O(n^2) why?
Because after each loop run n is added to i. So it has to run maximal n times to reach n², thus ending the loop.
O(n^2) would be:
i=1;
while(i<n*n)
i=i+1;

Can someone explain to me what to do here

I don't want the answer I want to know how to do it.
The efficiency of the algorithm doIt can be expressed as O(f(n))=n^3. Calculate the efficiency of the following program segment exactly and by using the big-O notation.
for (i=1; i<=n+1; i++)
for (j=1; j<n, j++)
doIt (...)
The example he gave us wasn't anything like this he just drew several squares inside of other squares which showed us that it was a nested loop. He didn't give us any type of code like the one in the problem. He just wrote
Alg(m, n, k, l)=3n^3
M=1n, N=1 2n, K=1n, L=1n^2
n^2*n*2n*n*3n^3=6n^8=O(n^8)
So, I'm assuming that this is a nested loop and the highest it goes to is n^3.
Or can someone write the code for the example so I can understand it better?
for (i=1; i<=n+1; i++)
for (j=1; j<n, j++)
doIt (...)
As you mentioned the worst-case complexity is given to be O(n^3).
So, in case of nested loops, the main thing to focus is that the first loop guides the inner loop,i.e., the inner loop will generally run no. of iterations(not necessarily always) than the outer loop!
As in your question, the outer loop runs for i=1 to i=n+1---n+1 times. Similarly, the inner loop runs for j=1 to j < n --- n-1 iterations on each iteration of outer loop .
Also, the function doIt() is inside the inner loop with complexity of order O(n^3).
Next, n+1 iterations are of order O(n) as per worst-case complexity.
Similarly, n-1 iterations are of order of O(n) as per worst-case complexity!
Hence, the overall worst-case complexity = O(n)*O(n)*O(n^3) = O(n^5)...
If you're unable to understand,please leave a comment below!

Time complexity of this function

I am pretty sure about my answer but today had a discussion with my friend who said I was wrong.
I think the complexity of this function is O(n^2) in average and worst case and O(n) in best case. Right?
Now what happens when k is not length of array? k is the number of elements you want to sort (rather than the whole array).
Is it O(nk) in best and worst case and O(n) in best case?
Here is my code:
#include <stdio.h>
void bubblesort(int *arr, int k)
{
// k is the number of item of array you want to sort
// e.g. arr[] = { 4,15,7,1,19} with k as 3 will give
// {4,7,15,1,19} , only first k elements are sorted
int i=k, j=0;
char test=1;
while (i && test)
{
test = 0;
--i;
for (j=0 ; j<i; ++j)
{
if ((arr[j]) > (arr[j+1]))
{
// swap
int temp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
test=1;
}
} // end for loop
} // end while loop
}
int main()
{
int i =0;
int arr[] = { 89,11,15,13,12,10,55};
int n = sizeof(arr)/sizeof(arr[0]);
bubblesort(arr,n-3);
for (i=0;i<n;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
P.S. This is not homework, just looks like one. The function we were discussing is very similar to Bubble sort. In any case, I have added homework tag.
Please help me confirm if I was right or not. Thank you for your help.
Complexity is normally given as a function over n (or N), like O(n), O(n*n), ...
Regarding your code the complexity is as you stated. It is O(n) in best case and O(n*n) in worst case.
What might have lead to misunderstanding in your case is that you have a variable n (length of array) and a variable k (length of part in array to sort). Of course the complexity of your sort does not depend on the length of the array but on the length of the part that you want to sort. So with respect to your variables the complexity is O(k) or O(k*k). But since normally complexity notation is over n you would say O(n) or O(n*n) where n is the length of the part to sort.
Is it O(nk) in best and worst case and O(n) in best case?
No, it's O(k^2) worst case and O(k) best case. Sorting the first k elements of an array of size n is exactly the same as sorting an array of k elements.
That's O(n^2), the outer while goes from k down to 1 (possibly stopping earlier for specific data, but we're talking worst case here), and the inner for goes from 0 to i (which in turn goes up to k), so multiplied they're k^2 in the worst case.
If you care about the best case, that's O(n) because the outer while loop only executes once then gets aborted.

Resources