Big O Notation for sorted insertion - java

Here's the code for orderedInsertion for an array:
public void orderedInsert(int x){
int i =0;
for(i=0;i<count;i++) if(arr[i]>x) break;
for(int j=count-1;j>=i;j--) arr[j+1] = arr[j];
arr[i]=x;
count++;}
If instead of using a break right after the IF statement, I did implement the second for loop ( the one with j variable immediately as follows:
EDITED CODE:
public void orderedInsert(int x) {
boolean flag = false;
int i =0;
for (i=0; i<count; i++) {
if (arr[i]>x) {
for (int j=count-1; j>=i; j--) {
arr[j+1] = arr[j];
arr[i] = x;
count++;
flag = true;
}
if (flag)
break;
}
}
}
Would both algorithms run in O(N)? This is what makes sense to me, but my instructor said "if you see two nested loops, this means it runs O(N^2).
What makes sense to me is that even in the worst case scenario we will only traverse N times.

This case it seems that these two algorithms is O(n) even though they are not similar. Count is being used differently, it looks like the first one uses count perhaps to show the size of the array that it changed. So if someone put an element in the array, count increments. But the second uses count for something else. Also the same for arr[i] = x;. First one seems to set it once, while the second one continues to set it.
A typical case of nested loop is like the following:
for(int j=count-1;j>=i;j--)
like if count = 100
for(int j=100-1;j>=0;j--) // 100 times it must iterate
//then i turns to 1
for(int j=100-1;j>=1;j--) //must iterate 99 times
etc...
If it was just one loop it will iterate only 100
for(i=0;i<count;i++) //iterate 100 times that is it, its done
but with a nested loop it iterates
when i=0 : it iterates 100 times
when i=1 : it iterates 99 times
when i=2 : it iterates 98 times
So in other words, if there was just one loop here it will only iterate 100 times
But with this nested loop it is looping 100 times + 99 times + 98 times etc. This is most likely especially 'if(arr[i]>x) break;' never happens
Also according to Big Oh notation, if something takes (n(n-1))/2 times to complete, which this does, it is considered O(n^2)

Related

From 1 to N, print all the pairs of number that has sum larger than 50

I'm new to Java and I have an exercise like this. From 1 to N, print all the pairs of number that has sum larger than 50.
For example if N = 60, then the result will be something like (1,50);(1,51);...;(1,60);...;(2,49);(2,50);...;(2,60);....;(58,59);(58,60);(59,60). I'm thinking about some nested while loop with a run from 1 to N and b run from N to 1, then the condition is a+b>50. I think if a+b<50 it will be easier since I can set b = 50-a or something like that. Still I'm quite of confusing right now.
Take a look:
public static void main(String[] args) {
int N = 60;
for (int i=1; i<=N; i++) { //1st loop
for (int j=i+1; j<=N; j++) { //2nd loop
if (i+j > 50) {
System.out.printf("(%d, %d);", i, j);
}
}
System.out.println();
}
}
Explaination:
The first loop (index i) is going over all of the numbers in allowed range N. The second loop (index j) is going over all of the other numbers in said range, that are bigger than i. We're taking only bigger numbers so we don't go over the same pair twice. Finally only the pairs that are qualified by your condition (bigger than 50) are printed.
On a side note: I implore that you work on your "googling" skills. Knowing how to search info online is an essential skill. By a search and a quick read, you could find links that while not directly solve your problem, does get you a step in the right direction.
Edit: Worth noting that I'm not sure this code prints the pairs the exact way you want it to. It also doesn't consider pairs of the same number (e.g. (26, 26)). It wasn't clear to me if you're intreseted in these cases or not by your question.

What will be time complexity for the given algorithm?

We were given the problem for which I came up with a solution. Could somebody help me identify the time complexity for the given solution? Should it be O(n) or O(n^2)? According to me it should be O(n).
Problem
Write a program to print the sum of the elements of an array following the given
below condition.
If the array has 6 and 7 in succeeding orders, ignore the numbers between 6 and 7 and consider the other numbers for calculation of sum.
Eg1) Array Elements - 10,3,6,1,2,7,9
O/P: 22
[i.e 10+3+9]
Eg2) Array Elements - 7,1,2,3,6
O/P:19
Eg3) Array Elements - 1,6,4,7,9
O/P:10
Solution
outer: for (i = 0; i < elementsCount; ++i) {
if (arr[i] == 6) {
int sumBetweenBounds = arr[i];
for (j = i + 1; j < elementsCount; ++j) {
if (arr[j] == 7) {
i = j;
continue outer;
}
sumBetweenBounds += arr[j];
}
sum += sumBetweenBounds;
continue;
}
sum += arr[i];
}
When talking about time complexity, we should differentiate between best-case, worst-case or average-case scenario (https://en.wikipedia.org/wiki/Best,_worst_and_average_case). When it is not mentioned, worst-case scenario is usually intended.
In the worst-case scenario, your algorithm is O(n^2) because of the inner loop running when the array element is 6. In the worst-case, all array elements could be this value.
In the best-case scenario, it is O(n), but this is usually not interesting.
For average-case analysis, you would need to know the distribution of values in all arrays that your algorithm will be run on.
First, your algorithm wont work for an array of only 6's.
Second, Your algorithm complexity is O(n^2), check the case of an array of only 6's.
If there are only 6's you'll keep getting into the inner loop for every element which will give you the mentioned complexity and also keep summing up 6's that you already summed up before.
For example:
int[] arr = new int[]{6,6,6,6};
will give:
//1st iteration
sum += 6+6+6+6;
//2nd iteration
sum += 6+6+6;
//3rd
sum += 6+6;
//4th
sum += 6;
Which in total gives sum=60 instead of 24.
You make solution more complicated that actually problem, you should have use single for loop and you could have used boolean to check weather you want to add element or not

What counts as a comparison in algorithm analysis?

MAIN QUESTION: When keeping track of comparisons, what actually counts as a comparison? Should I only count comparisons between array items since that's what the algorithm is meant for or is it more widely accepted to count every single comparison?
Currently, I am trying to wrap my head around the fact that I'm told that the theoretical number of comparisons for the worst case bubble sort algorithm is as follows:
Amount of comparisons:
(N-1) + (N-2) + (N-3) + ... + 2 + 1 = (N*(N-1))/2 = (N^2-N)/2 < N^2
So according to the formula (N^2-N)/2, with an input size (N) of 10, I would get a total of 45 comparisons. However, it is mentioned that this calculation only applies to the comparison operation in the inner loop of this pseudo code:
for i:=1 to N-1 do
{
for j:=0 to N-i do
{
if A[j] > A[j+1] // This is the comparison that's counted.
{
temp := A[j]
A[j] := A[j+1]
A[j+1] := temp
}
}
}
Now in Java, my code looks like this:
public int[] bubble(int[] array)
{
int comparisons = 0;
int exchanges = 0;
int temp;
int numberOfItems = array.length;
boolean cont = true;
comparisons++; // When pass == numberOfItems, a comparison will be made by the for loop that wouldn't otherwise be counted.
for (int pass=1; pass != numberOfItems; pass++)
{
comparisons = comparisons + 2; // Counts both the outer for loop comparison and the if statement comparison.
if (cont) // If any exchanges have taken place, cont will be true.
{
cont = false;
comparisons++; // Counts the inner for loop comparison
for (int index = 0; index != (numberOfItems - pass); index++)
{
comparisons++; // Counts the if statement comparison.
if (array[index] > array[index+1])
{
temp = array[index];
array[index] = array[index+1];
array[index+1] = temp;
cont = true;
exchanges++;
} // end inner if
} // end inner for
}
else
{
break; // end outer if
}
}
System.out.println("Comparisons = " + comparisons + "\tExchanges = " + exchanges);
return array;
}
After performing the worst case scenario on my code (using an array with 10 elements that are in the reverse order), I have gotten a total of 73 comparisons. This seems like a crazy high overshoot of the theoretical result which was 45 comparisons. This feels right to me though since I've accounted for all for loops and if statements.
Any help is greatly appreciated!
EDIT: I have noticed an error in my total comparison count for my inner loop. I wound up counting the inner loop twice before, but now it is fixed. Instead of getting 118 comparisons, I now get 73. However, the question still stands.
When measuring the number of comparisons in a sort, you only count comparisons between the array items. You count them whether or not they're actually in the array when you compare them.
The idea is that, instead of simple integers, the array might contain things that take a long time to compare. An array of of strings, for example, can be bubble-sorted using N(N-1)/2 string comparions, even though a single string comparison might require many other operations, including many comparisons of individual characters.
Measuring the performance of a sorting algorithm in terms of the number of comparisons makes the measurement independent of the type of things being sorted.
In evaluating sorting algorithms, it is common to count all comparisons between array elements as having equivalent cost, while ignoring comparisons between things like array indices. The basic concept is that in order for sorting operations to remain distinctly different from radix partitioning, the size of the items being sorted would need to increase as the number of them increased. Suppose, for example, one had an array of 1,000,000,000 char values and wanted to sort them. While one could use Quicksort, bubble sort, or something else, a faster approach would simply be to use an int[65536] and count how many of each value there are. Even if one needed to sort items which had char keys, the best way to do that would be to determine where to place the last item with a key of 0 (the number of items with a key of zero, minus one), where to place the last item with a key of 1 (number of items with keys of 0 or 1, minus one), etc. All such operations would take time proportional to the number of items plus the number of possible key values, without any lg(N) factor.
Note that if one ignores "bookkeeping" costs, algorithms like Quicksort aren't quite optimal. A sorting algorithm which is designed to maximize the amount of information gained from each comparison may do slightly fewer comparisons. Unless comparisons are very expensive, however, such a sorting algorithm would likely waste more time being "smart" than it would have spent being "stupid".
One issue I haven't seen discussed much, though I would think it could offer significant benefit in many real-world cases, would be optimizing sequences of comparisons between items that are known to be in a narrow range. If while performing a Quicksort on a series of thousand-character path names, one is processing a partition whose entries are all known to between two names that share the first 950 characters, there would be no need to examine the first 950 characters of any names in that partition. Such optimizations would not likely be meaningful in big-O terms unless key length was a parameter, but in the real world I would expect it could sometimes have an order-of-magnitude impact.
the comparison variable should only be incremented after the if statement has been reached in the execution of the code. The if statement is only reached if the condition stated in the outer and inner for loop have been met therefore the code should be like this.
Also dont forget to change the condition in the for loops from using != to <= The new java code:
public int[] bubble(int[] array)
{
int comparisons = 0;
int exchanges = 0;
int temp;
int numberOfItems = array.length;
boolean cont = true;
for (int pass=1; pass <= numberOfItems; pass++)
{
if (cont) // If any exchanges have taken place, cont will be true.
{
cont = false;
for (int index = 0; index <= (numberOfItems - pass); index++)
{
if (array[index] > array[index+1])
{ comparison++;
temp = array[index];
array[index] = array[index+1];
array[index+1] = temp;
cont = true;
exchanges++;
} // end inner if
} // end inner for
}
}
comparison++; // here you increment by one because you must also count the comparison that failed
System.out.println("Comparisons = " + comparisons + "\tExchanges = " + exchanges);
return array;
}

java: Big-Oh order of this do-while code fragment? Plus a tight upper bound

I know this is easy but my textbook doesn't talk about Big-Oh order with do-while loops, and neither do any of my other algorithm sources.
This problem states that the following code fragment is parameterized on the variable "n", and that a tight upper bound is also required.
int i=0, j=0;
do {
do {
System.out.println("...looping..."); //growth should be measured in calls to println.
j=j+5;
} while (j < n);
i++;
j = 0;
} while (i < n);
Can anyone help me with this and explain Big-Oh order in terms of do-while loops? Are they just the same as for loops?
A good maxim for working with nested loops and big-O is
"When in doubt, work from the inside out!"
Here's the code you have posted:
int i=0, j=0;
do {
do {
Do something
j=j+5;
} while (j < n);
i++;
j = 0;
} while (i < n);
Let's look at that inner loop. It runs roughly n / 5 times, since j starts at 0 and grows by five at each step. (We also see that j is always reset back to 0 before the loop begins, either outside the loop or at the conclusion of an inner loop). We can therefore replace that inner loop with something that basically says "do Θ(n) operations that we care about," like this:
int i=0;
do {
do Θ(n) operations that we care about;
i++;
} while (i < n);
Now we just need to see how much work this does. Notice that this will loop Θ(n) times, since i counts 0, 1, 2, ..., up to n. The net effect is that this loop is run Θ(n) times, and since we do Θ(n) operations that we care about on each iteration, the net effect is that this does Θ(n2) of the printouts that you're trying to count.

Analysis of array algorithm and its time complexity

I'm supposed to analyse this code and say something about its time complexity, but I am having trouble understanding what the code itself does, how does it change array a?
I also don't understand the following two operations:
1) foobar[a[i]]++;
So you replace the zeros in foobar with elements of array a? But what does the ++ do?
2)
a[outPos++]=1;
This increments outPos first, and leaves a[0] unchanged during the whole for loop?
public static void foo(int[] a, int b) {
int [] foobar = new int[b+1];
for (int i = 0; i<foobar.length; i++)
foobar[i]=0;
for (int i = 0; i<a.length; i++)
foobar[a[i]]++;
int outPos = 0;
for (int i=0; i<foobar.length; i++)
for (int j=0; j<foobar[i]; j++)
a[outPos++]=i;
}
As far as time complexity goes, I think it's O(n^2). The first two for loops run in constant time. But the worst case of the third nested loop seems to me that the last element in foobar is big, and then it would be quadratic?
It is an implementation of Counting Sort,
Where a[] stores the array to be sorted and b is the maximum integer in a[]
foobar[] is the counting array which is of size b
Let N = sizeof(a), M = b for common notation,
The first two loops:
Initializing counting array to zeros O(M)
Count the elements, say if there is 3 '10's in a[], foobar[10] = 3, O(N)
The tricky third loop:
Outer loop, without doubt, O(M)
Inner loop, you have to consider the total(maximum) # of time that j can be increased: which is Sum(foobar[]) = sizeof(a) = N, so indeed this loop, throughout whole outer loop iteration, is bound to be executed N times at most. So both loops as a whole is O(N+M), instead of intuitively O(NM)
So total complexity is: O(N) + O(M) + O(N+M) = O(N+M).
A tips if you found the third loop complexity is hard to understand, think in a way like this:
It is a 0-sum game. If some foobar[z] is large, then there is many foobar[j] = 0 which almost means skip the inner loop for such i. Otherwise, all foobar[j] will be about at average size.
It is hard to analysis per iteration of i, but it is easy to analysis the inner loop as a whole, as we know the total sum of foobar[] is a constant.
This looks like a counting sort implementation. Considering that N (number of items) is the length of array a, and M (largest possible item) is b, its time complexity is O(N+M).

Categories