What is supposed to be the Time Complexity of this loop - java

What should be the time complexity of this code?
I am thinking (n^2 -n) as the loop will run n(n-1)/2 times.
for (int i = 0; i < n-1; i++) {
for (int j = i + 1; j < n; j++) {
System.out.println(i + "i " + j + " j");
}
}

i: outer loop runs n - 1 times
j: inner loop runs n - (i + 1) times
Analyze it with a small number, say n = 10.
The outer loop will run 9 times.
The inner loop will run as follows
i = 0: 9 times
i = 1: 8 times
i = 2: 7 times
...
i = 8: 1 time
Therefore
n * ( n - 1) = n ^ 2 - n
For very large values of n, n is insignificant when compared to n squared.
See also wikipedia asymtotic analysis.

Related

Analyzing shell sort algorithm (big O)

This is the shell sort algorithm.
void shellSort(int array[], int n){
for (int gap = n/2; gap > 0; gap /= 2){
for (int i = gap; i < n; i += 1) {
int temp = array[i];
int j;
for (j = i; j >= gap && array[j - gap] > temp; j -= gap){
array[j] = array[j - gap];
}
array[j] = temp;
}
}
}
I'm certain that the outer loop of this algorithm runs logn times but I'm not sure with the middle loop and the innermost loop. This site https://stackabuse.com/shell-sort-in-java/ said that the middle loop runs n-gap times while the innermost loop runs i/gap but I'm not so sure about that. Please help me understand how the middle and innermost loop runs in this algorithm, thank you so much for anyone helping me this.
These are the loops in the algorithm:
for (int gap = n/2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i += 1) {
for (j = i; j >= gap && array[j - gap] > temp; j -= gap) {
}
}
}
Let's start with loop over i. It starts at gap and goes to n with increment of 1. The next loop over j starts at current i and goes down by gap until it becomes smaller than gap. So, the loop over j executes once for i between gap and 2*gap, twice for i between 2*gap and 3*gap, three time for i between 3*gap and 4*gap and so on.
That means that the j loop will execute once for gap different values of i, twice for gap different values of i, three times for gap different values of i, etc.
The maximum value for i is n, so the loop over j can execute at maximum j_max = (n - gap)/gap times. Total number of executions of the j loop is
1+1+...+1+1 + 2+2+...+2+2 + 3+3+...+3+3 + .... + j_max+j_max+...+j_max+j_max
|_________| |_________| |_________| |_________________________|
gap times gap times gap times gap times
This sum is equal to
gap*(sum from 1 to j_max) = gap * j_max(j_max + 1) / 2 = O(gap * ((n-gap)/gap)^2) = O((n-gap)^2/gap)
This will be repeated for different values of gap in the outer loop, so the complexity is O-big of
sum((n-gap)^2/gap, for gap = n/2, n/4, n/8, ...., 4, 2, 1)
Expanding:
(n^2 - 2*n*gap + gap^2)/gap = n^2*(1/gap) - 2*n + gap
The first term is equal to n squared multiplied by the following values:
1/(n/2), 1/(n/4), 1/(n/8), ..... 1/4, 1/2, 1/1
or
2/n, 4/n, 8/n, ....., n/n
This is a sum of powers of two divided by n, so the first term gives in total
n^2/n * 2^(log2 n) = n^2
The second term is -2*n summed log2 n times, so complexity is
n*log2 n
The last term is sum of gaps, so it's sum of powers of two and its complexity is n.
Combining all together we get the worst case complexity as O(n^2).
In each iteration, the middle loop starts at gap and ends at n. So the total number of iterations would be n - gap
The inner gap starts at i. In each iteration, it gets reduced by gap.
Suppose i = 15 and gap = 3, then values of j in subsequent iterations would be 15,12,9,6,3. Which is 5 iterations. Therefore i/gap iterations in the worst case.
The formula for finding number of terms in an arithmetic sequence is
(last term - first term) / difference + 1
for (int i = gap; i < n; i += 1)
starts at i = gap and exits when i == n. Last value i can take is n - 1.
Every loop, i is incremented by 1, so this loop gets executed (n - 1 - gap) / 1 + 1 = n - gap times
for (j = i; j >= gap && array[j - gap] > temp; j -= gap)
This loop starts at j = 1 and exits when j < gap (ignore the second part by assuming worst case senario). The last value j can take is gap.
Every loop, j is decremented by gap, so this loop gets executed (i - gap)/gap + 1 = i

Calculating Big O complexity of these algorithms?

I am trying to figure out the Big O notation of the following 2 algorithms below but am having trouble.
The first one is:
public static int fragment3 (int n){
int sum = 0;
for (int i = 1; i <= n*n; i *= 4)
for (int j = 0; j < i*i; j++)
sum++;
return sum;
} //end fragment 3
The answer should be O(n^4). When I try to do it myself this is what I get:
I look at the first for loop and think it runs n^2 logn times. Then for the inner for loop, it runs n times + the run time of the outer loop which is n^3 logn times. I know this is wrong but just don't get it.
For the code fragment below, the answer is O(n^9).
public static int fragment6(int n) {
int sum = 0;
for(int i=0; i < n*n*n; i++) {
if(i%100 == 0) {
for(int j=0; j < i*i; j += 10)
sum++;
} // if
else {
for(int k=0; k <= i; k++)
sum++;
} // else
} // outer loop
return sum;
} // fragment 6
When I attempt it I get: n^3 for the outer for loop. for the if statement I get n, for the second for loop I get n + the other for loop and if statement, making it n^5. Finally, I get n for the final for loop and everything adds up to O(n^6).
What am I doing wrong and what is the correct way to get its O(n^9) complexity?
For the first one.
Let's look at the inner loop..
At the first iteration of the outer loop (i=1) it runs 1 time. At the second iteration (i=4) it runs 16 (4*4) times. At the third iteration (i=16) it runs 256 (16*16) times. In general, at the (k+1)-th iteration of the outer loop inner loop runs times, as at that iteration. So the total number of iterations will be
Now, how many numbers in that sum we will have? To determine that we should have a look at the outer loop. In it i grows as , until it reaches . So the total number of iterations is .
This means that the total number of runs of inner loop is
(by dropping all the numbers from the sum but the last one).
Now we know, that the inner loop runs at least times, so we are not faster than O(n^4).
Now,
Solving for N,
where C is a constant, so we're not slower than O(n^4).
Your approach to computing big-O is flat-out wrong, and you've made computation errors.
In some common cases you can take the worst case number of iterations and multiply them together, but this isn't a sound method and fails for cases like this:
for (i = 1; i < n; i *= 2) {
for (j = 0; j < i; j++) {
sum++;
}
}
Here, the outer loop runs log_2(n) times, and the inner loop worst case is n iterations. So the wrong method that you're using will tell you that the complexity of this code is O(n log n).
The correct method is to count accurately the number of iterations, and approximate at the end only. The number of iterations is actually:
1 + 2 + 4 + 8 + ... + 2^k
where 2^k is the largest power of two less than n. This sum is 2^(k+1) - 1, which is less than 2n. So the accurate complexity is O(n).
Applying this idea to your first example:
for (int i = 1; i <= n*n; i *= 4)
for (int j = 0; j < i*i; j++)
sum++
i takes the values 4^0, 4^1, 4^2, ..., 4^k where 4^k is the largest power of 4 less than or equal to n^2.
The inner loop executes i^2 times for a given value of i.
So overall, the inner sum++ is executed this many times:
(4^0)^2 + (4^1)^2 + ... + (4^k)^2
= 2^0 + 4^2 + ... + 4^2k
= 16^0 + 16^1 + ... + 16^k
= (16^k - 1) / 15
Now by definition of k we have n^2/4 < 4^k <= n^2. So n^4/16 < 4^2k <= n^4, and since 16^k = 4^2k, we get that the total number of times the inner loop is executed is O(16^k) = O(n^4).
The second example can be solved using a similar approach.
First case:
Last run of the inner-loop with i = n^2, runs for n^4. The outer-loop up to n^2, but using exponential growth. For summation the sum over all inner-loop runs but the last is less than the last run. So inner-loop is essentially contributing O(1).
Second case:
100 % n == 0 does not matter really in O thinking
else part does not matter, it is much less than main part
outer-loop runs from 0 to n^3 => n^3
inner-loop runs from 0 to n^6 => n^6
outer-loop times inner-loop => n^9

Big O Notation of Java Nested Loops

I am aware of the various rates of Big O such as O(n^2) and O(n), and have no problem determining the Big O value of simple nested for loops such as the following.
for (int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
//Simple Statement
The following loop is clearly O(n^2), but how does one go about solving for Big O when the inner nested loop is dependent on the outer loop.
Example
for ( int i = 0; i < n; i++)
for (int j = n - 1; j >= i; j--)
//Simple Statement
would T(n) simply be n*(n-1-i) ?
Thanks in advance for the help!
It is still on the order of n^2. You only care about the most significant term. The second expression would look something line O(n^2 - an) where a is some sort of coefficient. All you really care about is the n^2.
The inner loop runs n + (n-1) + (n-2) + ... + 2 + 1 times. This is a Gaussian sum and equals n * (n + 1) / 2, or (n^2 + n) / 2, hence O(n^2).

Why does the for loop output this?

I am just very confused from this homework problem. I do not understand why the values of i and sum come out this way. I just do not understand the concept of the algorithm here, can someone please explain this?
int i = 0;
int sum = 0;
for(i=0; i < 5; i++)
{
sum += i;
}
System.out.println(i + "\n" + sum);
The output is:
5
10
----jGRASP: operation complete.
5 - because there are 5 iterations
10 - because the sum is 10 :)
Sum
Iteration 1: 0 + 0 = 0
Iteration 2: 0 + 1 = 1
Iteration 3: 1 + 2 = 3
Iteration 4: 3 + 3 = 6
Iteration 5: 6 + 4 = 10
Verification code
int i = 0;
int sum = 0;
for (i = 0; i < 5; i++) {
System.out.println(String.format(
"Iteration %s: %s + %s = %s", (i + 1), sum, i, (sum + i)));
sum += i;
}
This code :
int i = 0;
int sum = 0;
for(i=0; i < 5; i++)
{
sum += i;
}
System.out.println(i + "\n" + sum);
output in sum this : 0 + 1 + 2 + 3 + 4 which is equal to 10 and i the number of iterations = 5.
You have created a variable i with value of 0 and then incrementing it 5 times in for-loop. So you got i's value as 5.
Now the value of sum is 0+1+2+3+4 which is 10
Because you iterate through your loop, which makes i == 5, then print it,
Sum goes as below, you are adding i to the previously calculated sum
0 + 1 = 1
1 + 2 = 3
3 + 3 + 6
6 + 4 = 10
Try put your print command inside the loop, they you can see better what's going on.
The only non-obvious thing is (in my opinion): i will be 5, because you used i++, which also incremented i by 1 even though the body did not execute after the last iteration. Inside the body i only can be maximum 4.
int sum = 0; int i = 0;
for (i = 0; i < 5; i++)
{
sum += i;
if (i == 5)
System.out.println("never executed");
};
Other answers tell the other things.

How to count the number of operations in a loop and give a theta characterization

I just want to make sure if I am doing this correct. I am trying to count the number of operations performed for the worst case scenario in java
int sum = 0;
for (int i = 0; i < n; i++ )
sum++;
Is the number of operations 2+3n or 3+3n?
I got the answer from counting int sum = 0 and int i = 0 for the "2" and i < n, i++, and sum++ as the "3n". Or is it a 3 rather than a 2 because I have to count i < n before going through the loop?
But either way, is the theta characterization going to be Θ(n)?
Now what if there is a nested for loop like this:
int sum = 0;
for (int i = 0; i < n; i++ )
for (int a = 0; a < i; a++)
sum++;
would it be 3+n*(6a+2) = 6na+2n+3? with Θ(n^2)?
if i change the inner for loop from a < i to a < i*i, would the equation still hold as above or change?
Maybe it's easier to count the number of executions of each statement if there's only one per line:
int sum = 0; // 1 time
int i = 0; // 1 time
while (i < n) { // n+1 times
sum++; // n times
i++; // n times
}
Hence, T(n) = 3*n+3 = Θ(n).
int sum = 0; // 1 time
int i = 0; // 1 time
while (i < n) { // n+1 times
int a = 0; // n times
while (a < i) { // 1 + 2 + ... + n = n*(n+1)/2 times
sum++; // 0 + 1 + ... + n-1 = n*(n-1)/2 times
a++; // 0 + 1 + ... + n-1 = n*(n-1)/2 times
}
i++; // n times
}
Hence, T(n) = 3*n+3 + n*(n-1) + n*(n+1)/2 = Θ(n^2).
I would it count as 3+3n, because when n = 0 then you execute the following 3 commands:
int sum = 0;
int i = 0;
i < n
Now when n != 0 then you execute the declarations once (2) and for each execution of the loop each command once (3n) and the final comparison (which fails; 1). That makes 3+3n.
And yes, that would be Θ(n) (and O(n) and o(n)).
Yes, exactly. Look here for a mathematical definition.
It doesn't matter if you use 2+3n or 3+3n. You have lim_n->infty ( (3+3n)/n ) = 3 (both lim sup and lim inf are the same here). Because of that limites (which is greater 0 and not infinity), you know that is Big Theta n.
In your second example, you cannot use the inner-loop variables (a or i). The amount of sum++ operations:
When i == 0: zero sum++s are executed.
When i == 1: exactly one sum++ get's executed (when a==0).
When i == 2: 2 sum++s (a==0 and a==1)
When i == 3: 3 sum++s (a==0, a==1 and a==2)
...
When i == n-1: n-1 sum++s (a==0, a==1, ... and finally a==n-1)
That are all sum++s in your code. So let's sum them together:
0 + 1 + 2 + ... + n - 1
That is the same as (n-1)(n-2)/2.
I.e. we have Θ(n^2 + n). The same thing for a++ and a < i (well, one more to be exact but that doesn't matter). The amount of i++ ops is just n. So you end up with Θ(n^2).
It'll be 3+3n, because the comparison runs for each value of i from 0 to n inclusive. I'd says that's O(n).

Categories