For the given code (I am using just one from my previous questions), the running time using O notation is O(n^2). If I want to express the running time using Theta notation would it be the same? Meaning Theta(n^2)?
for(int i=0; i<N; i++){
for(int j=1; j<N; j++){
System.out.println("Yayyyy");
if(i<=j){
System.out.println("Yayyy not");
}
}
}
In essence:
Big O-notation is for UPPER bounds for running time. This means that most algorithms have several Big O-bounds (your algorithm is for example O(n^23) because it is by far more effective than a theta(n^23) algorithm)
Theta-notation is for tight bounds. Not all algorithms have a clearly defined tight bound, because this would mean that it grows proportionally with the other function. In your example, because there is no way the algorithm can finish without having printed "Yayyy not"
(n^2 - n)/2 times, and it will never run more than this number of times, it will always grow proportionally with n^2, and thus have a theta(n^2) bound!
To make this short and palatable, BigO(n^2) means that your algorithm will not take longer than ~n^2 time. BigTheta(n^2) means that your algorithm will not take longer than ~n^2 time, and it will not take less than ~n^2 time.
Related
I am having trouble figuring out how to calculate the big O notation for a project. What would the big O notation be for a 3x3 grid, or a nxn grid with n being decided by the user.
Also, if I output a 3x3 grid multiple times, do I add the big O notations of each array together, or is there just one big O notation for all?
Sorry, I'm a little confused on how big O notation works and how to calculate it, and what parts of code it can be used for.
I really don't know what to do, this is the code for my multidimentional array.
String board[][] = new String[3][3];
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
board[i][j] = "-";
}
}
The algorithm that you made is initializing a multidimensional array. Although the array is filled by 9 of "-", the Big O Notation implies the upper bound on the complexity of the algorithm which is the maximum number of operations that the algorithm will perform given the worst-case input.
So, the input value that you have given (3x3) should not be considered to get the Big O Notation of your algorithms.
Since you have two iterations in your algorithms, the maximum iteration would be n*n, so your Big O is O(n^2).
Because your input data is given, which are 3 and 3, you can estimate the time complexity via O(n^2), which is O(9).
For more information: https://www.geeksforgeeks.org/difference-between-big-oh-big-omega-and-big-theta/
Time complexity describes how an algorithm's time grows, as a function of the input, as time approaches infinity.
In this case, it is clear that the running time depends only on the size of the input, not on its content. So it is up to you to define a variable that describes your input size.
In your code example, the input size is constant 3x3, so if this never changes, then you can just say the algorithm has constant time complexity, O(1).
If the input can change, then it is up to you to decide how it can change, and how it makes sense to define it. For example, you can say that it is an n * n quadratic grid. Fine. Then, clearly both your loops run n times, so you get a total complexity of O(n * n) = O(n2).
It is also perfectly correct to define n as the total number of elements in your array. Then, we have some n = a * b. One of your loops runs a times, the other b times, so in total the complexity becomes O(a * b) = O(n).
As for your second question, yes if you apply this for a board m times, then your complexity would be O(m n2) or O(m n), depending on your chosen definition.
What matters is that you make your definitions clear and define your variables in a way that makes sense for what you are trying to say.
Trying to brush up on my Big-O understanding for a test (A very basic Big-O understanding required obviously) I have coming up and was doing some practice problems in my book.
They gave me the following snippet
public static void swap(int[] a)
{
int i = 0;
int j = a.length-1;
while (i < j)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
Pretty easy to understand I think. It has two iterators each covering half the array with a fixed amount of work (which I think clocks them both at O(n/2))
Therefore O(n/2) + O(n/2) = O(2n/2) = O(n)
Now please forgive as this is my current understanding and that was my attempt at the solution to the problem. I have found many examples of big-o online but none that are quite like this where the iterators both increment and modify the array at basically the same time.
The fact that it has one loop is making me think it's O(n) anyway.
Would anyone mind clearing this up for me?
Thanks
The fact that it has one loop is making me think it's O(n) anyway.
This is correct. Not because it is making one loop, but because it is one loop that depends on the size of the array by a constant factor: the big-O notation ignores any constant factor. O(n) means that the only influence on the algorithm is based on the size of the array. That it actually takes half that time, does not matter for big-O.
In other words: if your algorithm takes time n+X, Xn, Xn + Y will all come down to big-O O(n).
It gets different if the size of the loop is changed other than a constant factor, but as a logarithmic or exponential function of n, for instance if size is 100 and loop is 2, size is 1000 and loop is 3, size is 10000 and loop is 4. In that case, it would be, for instance, O(log(n)).
It would also be different if the loop is independent of size. I.e., if you would always loop 100 times, regardless of loop size, your algorithm would be O(1) (i.e., operate in some constant time).
I was also wondering if the equation I came up with to get there was somewhere in the ballpark of being correct.
Yes. In fact, if your equation ends up being some form of n * C + Y, where C is some constant and Y is some other value, the result is O(n), regardless of whether see is greater than 1, or smaller than 1.
You are right about the loop. Loop will determine the Big O. But the loop runs only for half the array.
So its. 2 + 6 *(n/2)
If we make n very large, other numbers are really small. So they won't matter.
So its O(n).
Lets say you are running 2 separate loops. 2 + 6* (n/2) + 6*(n/2) . In that case it will be O(n) again.
But if we run a nested loop. 2+ 6*(n*n). Then It will be O(n^2)
Always remove the constants and do the math. You got the idea.
As j-i decreases by 2 units on each iteration, N/2 of them are taken (assuming N=length(a)).
Hence the running time is indeed O(N/2). And O(N/2) is strictly equivalent to O(N).
I'm having some trouble finding the big O for the if statement in the code below:
public static boolean areUnique (int[] ar)
{
for (int i = 0; i < ar.length-1; i++) // O(n)
{
for (int j = i+1; j < ar.length-1; j++) // O(n)
{
if (ar[i] == ar[j]) // O(???)
return false; // O(1)
}
}
return true; //O(1)
}
I'm trying to do a time complexity analysis for the best, worst, and average case
Thank you everyone for answering so quickly! I'm not sure if my best worst and average cases are correct... There should be a case difference should there not because of the if statement? But when I do my analysis I have them all ending up as O(n2)
Best: O(n) * O(n) * [O(1) + O(1)] = O(n2)
Worst: O(n) * O(n) * [O(1) + O(1) + O(1)] = n2
Average: O(n) * O(n) * [O(1) + O(1) + O(1)] = O(n2)
Am I doing this right? My textbook is not very helpful
For starters, this line
if (ar[i] == ar[j])
always takes time Θ(1) to execute. It does only a constant amount of work (a comparison plus a branch), so the work done here won't asymptotically contribute to the overall runtime.
Given this, we can analyze the worst-case behavior by considering what happens if this statement is always false. That means that the loop runs as long as possible. As you noticed, since each loop runs O(n) times, the total work done is Θ(n2) in the worst-case.
In the best case, however, the runtime is much lower. Imagine any array where the first two elements are the same. In that case, the function will terminate almost instantly when the conditional is encountered for the first time. In this case, the runtime is Θ(1), because a constant number of statements will be executed.
The average-case, however, is not well-defined here. Average-case is typically defined relative to some distribution - the average over what? - and it's not clear what that is here. If you assume that the array consists of truly random int values and that ints can take on any integer value (not a reasonable assumption, but it's fine for now), then the probability that a randomly-chosen array has a duplicate is 0 and we're back in the worst-case (runtime Θ(n2)). However, if the values are more constrained, the runtime changes. Let's suppose that there are n numbers in the array and the integers range from 0 to k - 1, inclusive. Given a random array, the runtime depends on
Whether there's any duplicates or not, and
If there is a duplicate, where the first duplicated value appears in the array.
I am fairly confident that this math is going to be very hard to work out and if I have the time later today I'll come back and try to get an exact value (or at least something asymptotically appropriate). I seriously doubt this is what was expected since this seems to be an introductory big-O assignment, but it's an interesting question and I'd like to look into it more.
Hope this helps!
the if itself is O(1);
this is because it does not take into account the process within the ALU or the CPU, so if(ar[i] == ar[j]) would be in reality O(6), that translates into O(1)
You can regard it as O(1).
No matter what you consider as 'one' step,
the instructions for carrying out a[i] == a[j] doesn't depend on the
value n in this case.
This question already has answers here:
What is a plain English explanation of "Big O" notation?
(43 answers)
Closed 9 years ago.
I really can't figure out what "Big-O" is and how to use it in practice, so i hope someone could give me a simple explaining and maybe a little programming example in java.
I have the following questions:
What does these terms mean (as simple as possible) and how is it used in java:
BigO(1), BigO(n), BigO(n2) and BigO(log(n)) ?
How do you calculate a Big-O from an existing java code?
How do you use Big-O sorting
How do you use Big-O recursion
Hope someone will be able to help.
Thank you in advantage
Big O is used to give an idea of how fast an algorithm will scale as input size increases
O(1) means that as input size increases, the running time will not change
O(n) means that as input size doubles, the running time will double, more or less
O(n^2) means that as input size double, the running time will quadruple, more or less
O(f(n)) means that as input size doubles, the running time will increase to around f(2n)
Regarding Big-O, sorting, and recursion.
Big-O sorting isn't really an algorithm. You can however use Big O to tell you how fast your sorting algorithm is.
For computing Big-O of a recursive function, I would recommend using the Master Theorem.
Guidelines for determining Big O:
Usually, you need to determine what your input size is (like array length, or number of nodes in your linked list, etc)
Then ask yourself, what happens if your input size doubles? Or triples?
If you have a for loop that goes through each element:
//say array a has n elements
for (int i = 0; i < n; i++) {
// do stuff
a[i] = 3;
}
Then doubling n would make the loop run twice as long, so it would be O(n). Tripling n would triple the time it takes, so the code scales linearly with the input size.
If you have a 2D array and nested for loops:
// we say that each dimension of the array is upper bounded by n,
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// do stuff
a[i][j] = 7;
}
}
As n doubles, the code will take 2^2 = 4 times as long. If input size triples, code will take 3^2 = 9 times as long. So Big O is O(n^2).
The Big-O notation is a notation made for showing computer algorithm performance, when the input is very large.
Three quick programming examples, in Java:
O(1):
for (int i=0; i<3; i++) {
System.out.println(i);
}
O(n):
int n = 1000000; /* Some arbitrary large number */
for (int i=0; i<n; i++) {
System.out.println(i);
}
O(n2):
int n = 1000000; /* Some arbitrary large number */
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
System.out.println(i * j);
}
}
Read more: http://en.wikipedia.org/wiki/Big_O_notation
Big O (it is the letter O - which is big- as opposed to the letter o which is small) gives an idea of how an algorithm scales when the input size (n) changes. The numbers are
If for instance n doubles from say 100 to 200 items,
an O(1) algorithm will take approximately the same time.
an O(n) algortihm will take double the time.
an O(n^2) algorithm will take four times the time (2^2)
an O(n^3) algorithm will take eight times the time (2^3)
And so on.
Note that log(n) can be understood as "the number of digits in n". This means that if you from n having two digits (like 99) to n having the double number of digits (four digits like 9999) the running time only doubles. This typically happens when you split the data in two piles and solve each separately and merge the solutions back, for instance in sorting.
Typically each loop over the input data multiply by n. so a single loop is O(n) but if you need to compare every element to every other element you get O(n^2), and so on. Note that the times are relative so a slow O(n) algorithm may be outperformed by a fast O(n^2) algorithm for small values of n.
Also note that O is worst case. So quicksort which generally run fast still is O(^2) because there is pathetic input data which cause it to compare every element to every other.
This is interesting because most algorithms are fast for small data sets, but you need to know how they work with input data perhaps thousands or millions of times larger where it is important if you have O(n^2) or O(n^3) or worse. The numbers are relative so it does not say anything bps out if a given algorithm is slow or fast, just how the worst case looks like when you double the input size.
How can i measure the performance of my java algorithm effectively ? is there any accurate way of doing it?
i read other questions of same kind but not satisfied.
any help would be appreciated.
long reference=System.nanoTime();
your_funct();
long finishm=System.nanoTime();
System.out.println( ( (double)(finishm-reference) )/1000000000.0); //in seconds
Has a meaningful level of ~0.003 seconds in my machine. I mean, you measure in nano-seconds but smallest step is around 3000000 nanoseconds in my machine.
You ask for performance which indicates some sort of timing. But then what would you compare against?
A general way of measuring an algorithm is using Big O, which takes a simplified mathematical approach.
To explain this at a very basic level a simple linear search of a list of integers has a linear (n) worst case big o. Eg:
for(int i = 0; i < sizeofarray; ++i)
if(array[i] == to_find)
return i;
At the worst case this would take i iterations (often number is referred to as n in big o) - so we call it n or linear complexity algorithm.
Something like a bubblesort algorithm is a loop within a loop so we have n * n complexity = n^2 or quadratic complexity.
Comparing like with like, if we just consider sorting, quicksort is more efficient than quadratic complexity (it is n log n complexity) so you can consider quicksort being 'better' than bubblesort.
So when evaluating your algorithm think about it in terms of n. Is there a loop? how many? The fewer the better. No loops even better - constant big o.
You can use some profilers. Many IDEs (such as Netbeans) have one.
If can make it practical or theoretical. If practical then put a timer before the algorithm starts and stop it when it ends. If theoretical then use Big O notation (isn't that hard) and you'll get an estimate of its time or space complexity.
The best way to do it is still java.lang.System.currentTimeMillis() as it will work regardless the IDE you are using.