What is the time complexity of the below function? - c

void fun(int n, int arr[])
{
int i = 0, j = 0;
for(; i < n; ++i)
while(j < n && arr[i] < arr[j])
j++;
}
The answer given is: variable j is not initialized for each value of variable i, so time complexity is O(n)
I don't quite understand it. Can anyone explain?

See the difference between your function and this (this is in O(n2) time complexity) -
void fun(int n, int arr[])
{
int i = 0, j = 0;
for(; i < n; ++i)
{
j = 0;
while(j < n && arr[i] < arr[j])
j++;
}
}
In your function the variable j is not initialized for each value of variable i. So, the inner loop runs at most n times.
Edit 1- From j=0 to j=n is maximum n iterations of inner while loop. Since you never initialize j again once j=n the inner while loop will never iterate. So at maximum (it could be less depending on the second condition arr[i] < arr[j]) you have n iterations of inner while loop once. The outer for loop will obviously iterate n times . So you have n+n=2n and not n2 even in the worst case.
Edit 2- #Kerrek SB answer to this is spot-on -
"The code finishes when j has been incremented n times. j never gets decremented, and at most n attempts are made at incrementing it (via i)"

The outer loop is executed n times.
The inner loop only continues if j < n, and since j is incremented in each step, it cannot be executed more than n times in total.

Related

C insertion sort stuck in while loop

I'm writing a simple program to sort a small array but when I run my code for insertion sort the program just runs forever.
It's probably a problem with the while loop. I ran through the program on paper and looked over some other people's code but I can't figure out why it's not working.
void mySort(int d[], unsigned int n){
int i, j, k;
for (j = 1;j < n;i++){
k = d[j];
i = j-1;
while (d[i] > k && i >=0){
d[i+1] = d[i];
d[i] = k;
i = i - 1;
}
}
}
for (j = 1;j < n;i++){
You compare value j, but you increment value i.
If you Use a Debugger, you would immediately notice that the value j does not get updated, and you'd find your problem immediately!!
Always Use a Debugger
The error is in your for loop.
for (j = 1;j < n;i++){
So your terminating conditions of the for loop are that j >= n, except you never change j or n after this statement.
Try
for (j = 1;j < n;j++){

Nested loop when inner loop index unequal outer loop index

Nested loop logic to skip the inner loop when its index equals the outer loop index.
Used an if statement within the inner loop to the effect of:
for (i=0;i<N;i++)
for (j=0;j<N;j++)
if (j!=i)
... some code
I believe this gives me the expected results but is there a less CPU consuming method that I may not be aware of?
If you can assume that N <= i, you can split the inner loop into 2 separate for loops to reduce the number of tests:
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++) {
... some code
}
/* here we have j == i, skip this one */
j++;
for (; j < N; j++) {
... same code
}
}
This results in more code but half as many tests on j. Note however that if N is a constant, the compiler might unroll the original inner loop more efficiently. Careful benchmarking is the only way to determine if this solution is worth the effort for your problem, compiler and architecture.
For completeness, this code can be simplified as:
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++) {
... some code
}
/* here we have j == i, skip this one */
while (++j < N) {
... same code
}
}

Big O Notation with function composition

I'm trying to determine the Big O notation of the following function
public static int f10(int n)
{
return f1(n*n*n)
}
Where f1() is given by:
public static int f1(int n)
{
int sum = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
sum++;
for (int j = 0; j < n; j++)
sum++;
for (int j = 0; j < n; j++)
sum++;
}
return sum;
}
I can see that O(f1) is O(n^2), but when we call f10, does this become O(n^6) because the size of n is being cubed before calling f1?
I understand the complexity of f1 is not changing from it's own perspective, but is it from f10's perspective of 'n'?
Let's analyse f1():
for (int i = 0; i < n; i++) -> O(n)
for (int j = 0; j < n; j++)
for (int j = 0; j < n; j++)
for (int j = 0; j < n; j++) -> O(n)
for (n-times) { O(n) } -> O(n^2)
So f1() is O(n^2). It's just two nested loops. But because f1() is called with n^3, make f10() indeed O(n^6).
However, the above complexity order is theoretical. In practice it may depend on how you call f10() and/or what optimizations the compiler makes. A smart C compiler could replace f1() with a simple and O(1) arithmetic expression.
Then, having f1() reduced to an expression, the compiler could replace calls like f10(42) with the result, doing all calculations at compile-time.
Do you see what I mean; how would you simplify f1() to a simple O(1) expression?
Complexity of f1 is always O(n^2), that's clear. However, the complexity of f10 is indeed O(n^6), because it relies on f1 invoked with an argument n^3. For the sake of simplicity, imagine that f1 is an inlined function. Body of f10 would then look like this:
public static int f10(int n)
{
int sum = 0;
for (int i = 0; i < n^3; i++) {
for (int j = 0; j < n^3; j++)
sum++;
for (int j = 0; j < n^3; j++)
sum++;
for (int j = 0; j < n^3; j++)
sum++;
}
return sum;
}
Now it is easy to deduce - two levels of nested loops, each with n^3 iterations -> O(n^6). If you are still not convinced, try to see how the running time of f10 increases with increased input:
n = 1 -> 3 iterations
n = 2 -> 8 * 3 * 8 = 3 * 2^6 iterations
n = 3 -> 27 * 3 * 27 = 3 * 3^6 iterations
....
n = k -> k^3 * 3 * k^3 = 3 * k^6 iterations

Average Time Complexity of Nested Loop

I'm trying to find the time complexity of the following function:
for (int i = 0; i < arraySize; i++) {
for (int j = 0; j < arraySize; j++) {
if (array[j] < array[i]) {
//Do something
}
else if (array[j] == array[i]) {
//Do something else
}
}
}
I think it is O(n^2), but I'm not sure how to prove it.
You are correct. It is O(n^2).
Rule of thumb: Simple programs can be analyzed by counting the nested loops of the program. A single loop over n items yields f( n ) = n. A loop within a loop yields f( n ) = n^2. A loop within a loop within a loop yields f( n ) = n^3.
You can also check with the link below for,
How to find time complexity of an algorithm
Hope this helps!

Will this modified partitioning algorithm in quicksort function the same as the original in all situations?

The code given in class for QuickSort partitioning procedure had two inner loops with an
empty body. Suppose we rewrite these loops by moving the increment/decrement from the
test into the body of the loop, and by modifying the initial values of the indexes accordingly.
The original and modified partitioning procedures are as follows:
int partition( A[], int l, int r )
{
int pivot = A[l];
int i = l, j = r+1;
while(i < j)
{
while (A[--j] > pivot);
while (A[++i] < pivot);
if (i < j) swap (A[i], A[j]);
}
swap(A[l], A[j]);
return j;
}
int partition( A[], int l, int r )
{
int pivot = A[l];
int i = l+1, j = r;
while (i < j)
{
while (A[j] > pivot) j--;
while (A[i] < pivot) i++;
if (i < j) swap(A[i], A[j]);
}
swap(A[l], A[j])
return j;
}
Does the modified partitioning procedure work correctly in all situations? (ignore the
glitch of i running off the array when the pivot is the maximal element). Hint: consider what
happens when the current subarray contains at least two other keys equal to the pivot.
The modified partitioning procedure gets into an infinite loop when the subarray contains at least two other values that are equal to the pivot.
Let's consider a case where we have:
int A[] = { 3, 3, 1, 3 };
And we call:
partition(A, 0, 3);
On the first iteration of the outer while loop, i is 1 and j is 3:
3 3 1 3
^ ^
i j
Consider the first test:
while (A[j] > pivot) j--;
It is not true that 3 is greater than 3, so j doesn't get decremented.
Now the second test:
while (A[i] < pivot) i++;
Similarly, it is not true that 3 is less than 3, so i doesn't get incremented.
When A[i] is swapped with A[j], the array doesn't change because the values at i and j are the same.
The loop starts a new iteration because i is still less than j. Because nothing has changed since the previous iteration, the loop will go through the same tests and do the same thing, which amounts to nothing. Thus the infinite loop.

Resources