Runtime analysis - c

int i, j;
for(i=0; i<n*n; i++)
{
if(i % n == 0)
for(j=0; j<n; j++)
x++;
else
x--;
}
I'm new to runtime analysis so I'm just checking my answer on here to see if I have the right idea.
I have to find a tight runtime bound for that segment and give a reasoning.
I came up with O(n²).
My reasoning behind it is because it runs the first for loop n² times. It only runs the second for loop if i is divisible by n.
Is this okay or am I completely wrong in my analysis?

The outer loop runs n² times. Every n-th run (so n runs in total), it starts another loop, which runs n times. That amounts to n² + n * n which equals 2n² which is a runtime of O(n²).

Related

Big O of nested loop that with varying iterations?

I'm having a bit of trouble figuring out the Big O run time for the two set of code samples where the iterations depend on outside loops. I have a basic understanding of the Big O run times and I can figure out the run times for simpler code samples. I'm not too sure how some lines are affecting the run time.
I would consider this first one O(n^2). However, I'm not certain.
for(i = 1; i < n; i++){
for(j = 1000/i; j > 0; j--){ <--Not sure if this is still O(n)
arr[j]++; /* THIS LINE */
}
}
I'm a bit more lost with this one. O(n^3) possibly O(n^2)?
for(i = 0; i < n; i++){
for(j = i; j < n; j++){
while( j<n ){
arr[i] += arr[j]; /* THIS LINE */
j++;
}
}
}
I found this post and I applied this to the first code sample but I'm still unsure about the second. What is the Big-O of a nested loop, where number of iterations in the inner loop is determined by the current iteration of the outer loop?
Regarding the first one. It is not O(n^2)!!! For the sake of simplicity and readability, let's rewrite it in the form of pseudocode:
for i in [1, 2, ... n]: # outer loop
for j in [1, 2, ... 1000/i]: # inner loop
do domething with time complexity O(1). # constant-time operation
Now, the number of constant-time operations within the inner loop (which depends on parameter i of the outer loop) can be expressed as:
Now, we can calculate the number of constant-time operations overall:
Here, N(n) is a harmonic number (see wikipedia), and there is a very interesting property of these numbers:
Where C is Euler–Mascheroni constant. Therefore, the complexity of the first algorithm is:
Regarding the second one. It seems like either the code contains a mistake, or it is a trick test question. The code resolves to
for (i = 1; i < n; i++)
for(j = i; j < n; j++){
arr[j]++;
j++;
}
The inner loop takes
operations, so we can calculate overall complexity:
For the second loop (which it appears that you still need an answer for), you have sort of a misleading bit of code, where you have 3 nested loops, so at first glance, it makes sense that the runtime is O(n^3).
However, this is incorrect. This is because the innermost while loop modifies j, the same variable that the for loop modifies. This code is actually equivalent to this bit of code below:
for(i = 0; i < n; i++){
for(j = i; j < n; j++){
arr[i] += arr[j]; /* THIS LINE */
j++;
}
}
This is because the while loop on the inside will run, incrementing j until j == n, then it breaks out. At that point, the inner for loop will increment j again and compare it to n, where it will find that j >= n, and exit. You should be familiar with this case already, and recognize it as O(n^2).
Just a note, the second bit of code is not safe (technically), as j may overflow when you increment it an additional time after the while loop finishes running. This would cause the for loop to run forever. However, this will only occur when n = int_max().

How do I find the time complexity (Big O) of while loop?

Code 1
int i = 0;
int j = 0;
while(i < n){
while(j < n){
printf("{%d,%d}",arr[i],arr[j]);
j++;
}
i++;
j = 0;
printf("\n");
}
Code 2
int result = 0;
int i = 0;
while (i < n / 2){
result += arr[i];
i += 1;
while (i >= n / 2 && i < n){
result += arr[i];
i += 1;
}
}
printf("%d\n", result);
I only know how to find time complexity with for loops, but I am uncertain about while loop.
It would be greatly appreciated if someone could help me find the total running time of each code.
A for loop, at the end of the day, IS a while loop. Something of the form:
for(int i=0; i<n; i++)
is equivalent to:
int i=0;
while(i<n)
{
i++;
}
In fact in pure mathematical analysis of algorithms you are supposed to make any for loop into a while loop in your algorithms (there are a couple reasons why).
Going back to your code. The analysis is simple:
Before the first iteration of the while loop the value of i is 0.
There exists a unique statement that updates the variable i (i++).
On every iteration of the outer loop i increases by 1.
The outer loop runs at most n times.
Before the iteration of any loop the value of j is 0.
There are 2 statements that update j (j=0 and j++)
Informally: we can tell before any iteration of the inner loop the value of j is 0.
Inside the inner loop the only statement that updates j is j++.
on every iteration of the inner loop j increases by 1.
The inner loop runs at most n times by the loop guard.
The outer loop runs at most n times, the inner loop runs at most n times for every iteration of the outer loop. All other statements are constant. The algorithm is in O(n*n)=O(n^2)
The second one is slightly more convoluted but:
Before the first iteration of the outer loop the value of i is 0.
Informally: the outer loop will run until the value of i is (n/2 - 1)
The update statement (i += 1) updates i to (n/2)
Informally: the inner loop runs (n-n/2 = n/2) times and it runs exactly once.
-The outer loop runs n/2 times, the inner loop runs n/2 times exactly once.
The algorithm thus runs O(n/2+n/2) = O(n) times
The first code sample is pretty much a classis for loop. Its complexity is O(n^2). This is because the inner loop has a complexity O(n) and it is run n times.
The second one is a bit more difficult, untill you see that is equivalent to a non nested loop (ignoring the complexity of the checks)
int result = 0;
int i = 0;
while (i < n){
result += arr[i];
i += 1;
}
printf("%d\n", result);
meaning its complexity is O(n)
The best approach to calculating time complexity is trying to actually understand how the algorithm works and counting the operations. In the second example, the inner loop never runs untill the outer loop is at its last iteration. And since they even execute the same code, the whole thing can be reduced to one loop.
Another good example is this:
for(i=0;i<n;i++){
for(j=i;j<n;i++){
//do something
}
}
Let's count the operations: 1 + 2 + 3 + 4 + ... + n. This comes down to n*n/2 leading to O(n^2)

Run time or a new idea

I need to write code that sorts in 'n' run time and I don't know how to calculate it. I need to simply sort an array so that left side is odd and right side is even. This is what I wrote and I wonder how do I to find the run time.
for (i=0;i<size-1;i++)
{
if(ptr[i]%2==0 || ptr[i]==0)
{
for (j=i;j<size;j++)
{
if(ptr[j]%2!=0)
{
temp=ptr[i];
ptr[i]=ptr[j];
ptr[j]=temp;
break;
}
}
}
}
Thanks in advance.
Your runtime for this Code is O(N^2)
You can use Counting Sort to sort an array in linear time
For reference Counting Sort
As #VenuKant Sahu answered, OP's code is O(n*n)
That is due to its double nested for loops
for (i=0;i<size-1;i++)
...
for (j=i;j<size;j++)
...
I need to write code that sorts in 'n' run time
O(n) algorithm (did not want to just give the code)
The number of loop iterations below can not exceed n/2.
The increment even_side happens at most n times.
The decrement odd_side happens at most n times.
// set up indexes
int even_side = left-most valid index
int odd_side = right-most valid index
loop {
while (the_even_index_is_not_at_the_right_end && is_even(a[even_side]) increment even_side;
while (the_odd_index_is_not_at_the_left_end && !is_even(a[odd_side]) decrement odd_side
compare the indexes
if (done) exit the loop;
a[even_side] <==> a[odd_side]
}
Some helper code to set up a random array.
#define N 10
srand(time(NULL));
int a[N];
for (int i = 0; i<N; i++) {
a[i] = rand()%100;
printf(" %d", a[i]);
}
puts("");

Loop Optimization in C

I have been tasked with optimizing a particular for loop in C. Here is the loop:
#define ARRAY_SIZE 10000
#define N_TIMES 600000
for (i = 0; i < N_TIMES; i++)
{
int j;
for (j = 0; j < ARRAY_SIZE; j++)
{
sum += array[j];
}
}
I'm supposed to use loop unrolling, loop splitting, and pointers in order to speed it up, but every time I try to implement something, the program doesn't return. Here's what I've tried so far:
for (i = 0; i < N_TIMES; i++)
{
int j,k;
for (j = 0; j < ARRAY_SIZE; j++)
{
for (k = 0; k < 100; k += 2)
{
sum += array[k];
sum += array[k + 1];
}
}
}
I don't understand why the program doesn't even return now. Any help would be appreciated.
That second piece of code is both inefficient and wrong, since it adds values more than the original code.
The loop unrolling (or lessening in this case since you probably don't want to unroll a ten-thousand-iteration loop) would be:
// Ensure ARRAY_SIZE is a multiple of two before trying this.
for (int i = 0; i < N_TIMES; i++)
for (int j = 0; j < ARRAY_SIZE; j += 2)
sum += array[j] + array[j+1];
But, to be honest, the days of dumb compilers has long since gone. You should generally leave this level of micro-optimisation up to your compiler, while you concentrate on the more high-level stuff like data structures, algorithms and human analysis.
That last one is rather important. Since you're adding the same array to an accumulated sum a constant number of times, you only really need the sum of the array once, then you can add that partial sum as many times as you want:
int temp = 0;
for (int i = 0; i < ARRAY_SIZE; i++)
temp += array[i];
sum += temp * N_TIMES;
It's still O(n) but with a much lower multiplier on the n (one rather than six hundred thousand). It may be that gcc's insane optimisation level of -O3 could work that out but I doubt it. The human brain can still outdo computers in a lot of areas.
For now, anyway :-)
There is nothing wrong on your program... it will return. It is only going to take 50 times more than the first one...
On the first you had 2 fors: 600.000 * 10.000 = 6.000.000.000 iterations.
On the second you have 3 fors: 600.000 * 10.000 * 50 = 300.000.000.000 iterations...
Loop unrolling doesn't speed loops up, it slows them down. In olden times it gave you a speed bump by reducing the number of conditional evaluations. In modern times it slows you down by killing the cache.
There's no obvious use case for loop splitting here. To split a loop you're looking for two or more obvious groupings in the iterations. At a stretch you could multiply array[j] by i rather than doing the outer loop and claim you've split the inner from the outer, then discarded the outer as useless.
C array-indexing syntax is just defined as (a peculiar syntax for) pointer arithmetic. But I guess you'd want something like:
sum += *arrayPointer++;
In place of your use of j, with things initialised suitably. But I doubt you'll gain anything from it.
As per the comments, if this were real life then you'd just let the compiler figure this stuff out.

Time complexity of the program

#include<stdio.h>
#include<time.h>
int main()
{
clock_t start;
double d;
long int n,i,j;
scanf("%ld",&n);
n=100000;
j=2;
start=clock();
printf("\n%ld",j);
for(j=3;j<=n;j+=2)
{
for(i=3;i*i<=j;i+=2)
if(j%i==0)
break;
if(i*i>j)
printf("\n%ld",j);
}
d=(clock()-start)/(double)CLOCKS_PER_SEC;
printf("\n%f",d);
}
I got the running time of 0.015 sec when n=100000 for the above program.
I also implemented the Sieve of Eratosthenes algorithm in C and got the running time of 0.046 for n=100000.
How is my above algorithm faster than Sieve's algorithm that I have implemented.
What is the time complexity of my above program??
My sieve's implementation
#define LISTSIZE 100000 //Number of integers to sieve<br>
#include <stdio.h>
#include <math.h>
#include <time.h>
int main()
{
clock_t start;
double d;
long int list[LISTSIZE],i,j;
int listMax = (int)sqrt(LISTSIZE), primeEstimate = (int)(LISTSIZE/log(LISTSIZE));
for(int i=0; i < LISTSIZE; i++)
list[i] = i+2;
start=clock();
for(i=0; i < listMax; i++)
{
//If the entry has been set to 0 ('removed'), skip it
if(list[i] > 0)
{
//Remove all multiples of this prime
//Starting from the next entry in the list
//And going up in steps of size i
for(j = i+1; j < LISTSIZE; j++)
{
if((list[j] % list[i]) == 0)
list[j] = 0;
}
}
}
d=(clock()-start)/(double)CLOCKS_PER_SEC;
//Output the primes
int primesFound = 0;
for(int i=0; i < LISTSIZE; i++)
{
if(list[i] > 0)
{
primesFound++;
printf("%ld\n", list[i]);
}
}
printf("\n%f",d);
return 0;
}
There are a number of things that might influence your result. To be sure, we would need to see the code for your sieve implementation. Also, what is the resolution of the clock function on your computer? If the implementation does not allow for a high degree of accuracy at the millisecond level, then your results could be within the margin of error for your measurement.
I suspect the problem lies here:
//Remove all multiples of this prime
//Starting from the next entry in the list
//And going up in steps of size i
for(j = i+1; j < LISTSIZE; j++)
{
if((list[j] % list[i]) == 0)
list[j] = 0;
}
This is a poor way to remove all of the multiples of the prime number. Why not use the built in multiplication operator to remove the multiples? This version should be much faster:
//Remove all multiples of this prime
//Starting from the next entry in the list
//And going up in steps of size i
for(j = list[i]; j < LISTSIZE; j+=list[i])
{
list[j] = 0;
}
What is the time complexity of my above program??
To empirically measure the time complexity of your program, you need more than one data point. Run your program for multiple values of N, then make a graph of N vs. time. You can do this using a spreadsheet, GNUplot, or graph paper and pencil. You can also use software and/or plain old mathematics to find a polynomial curve that fits your data.
Non-empirically: much has been written (and lectured in computer science classes) about analyzing computational complexity. The Wikipedia article on computational complexity theory might provide some starting points for further reading.
Your sieve implementation is incorrect; that's the reason why it is so slow:
you shouldn't make it an array of numbers, but an array of flags (you may still use int as the data type, but char would do as well)
you shouldn't be using index shifts for the array, but list[i] should determine whether i is a prime or not (and not whether i+2 is a prime)
you should start the elimination with i=2
with these modifications, you should follow 1800 INFORMATION's advice, and cancel all multiples of i with a loop that goes in steps of i, not steps of 1
Just for your time complexity:
You have an outer loop of ~LISTMAX iterations and an inner loop of max. LISTSIZE iterations. This means your complexity is
O(sqrt(n)*n)
where n = listsize. It is actually a bit lower since the inner loop reduces it's count eacht time and is only run for each unknown number. But that's difficult to calculate. Since the O-Notation offers an upper bound, O(sqrt(n)*n) should be ok.
The behaviour is difficult to predict, but you should take into account that accessing the memory is not cheap... it's probably faster to just calculate it again for small primes.
Those run times are too small to be meaningful. The system clock resolution is not accurate to that kind of level.
What you should do to get accurate timing information is run your algorithm in a loop. Repeat it a few thousand times to get the run time up to at least a second, then you can divide the time by the number of loops.

Resources