Is my runtime analysis of the code segment correct? - java

This is similar to this question runtime analysis of the following recursive method
I am trying to analyze this code segment
To analyze this, I saw that the outer loop was going to execute n/c times. And then for every time the outer loop runs, the inner loop will also execute n/c times. Therefore in total, this segment will run n^2/c^2 or O(n^2) if you drop the constant.
Is there also a visual way you can do this as well, similar to (from http://courses.cs.washington.edu/courses/cse373/15wi/lectures/lecture3.pdf) slide 19 ? I tried doing this but got (c *(n)(n + 1))/2 which I wasn't sure was right.

(c *(n)(n + 1))/2
= c*(n^2 + n)/2
= (c/2)*(n^2 + n)
dropping the constants and keeping the highest power of n gives a final answer of O(n^2)

For this problem, here is how would analyze it now
The most times that the outer loop will run is n⁄c and for everytime an iteration of the outer loop runs, the inner loop will also run at most n⁄c times.
Therefore the worst case Big O runtime of this algorithm is O(n2⁄c2) or O(n2)

Related

Runtime analysis for the partitioning of an array with Quicksort

Im working on a research paper about quicksort for school and thus I have to make a precise runtime analysis on best and worst case for my algorithm but im struggling with the part of my while-statements. I understand why its log(n) since you have so many recursive calls that you have n/2^k = 1 and this equation gives you n = 2^k, k = log2(n) and so on ... well since i did understand the recursive calls this part does not really matter but what matters is my following code:
}
}
I have to specify the "cost" for each statement in dependence of my elements n.
So i added a +1 for every if statement since they are simple statements and now i dont now how to get the cost for the while loops. The outer loop runs until the pointers i and j cross so the outer loop gets execuated at least n/2+1 (+1 for the exit condition) - but i cant find out how often the inner two while loops run. I thought that they would run also n/2 times but this cant work since our teacher taught us that we have to multiply the costs whenever we have nested statements which would result in a (n/2+1)*((n/2)+1)+((n/2)+1)) which is clearly n^2 and not O(n) ...
And yes i have to add a +1 for each abort condition and if statement altough they dont really matter ...
I hope you can help me by telling me whats my mistake that i get a O(n^2) runtime although it has to be O(n)
Side note: I think for the while-loops it doesnt matter if its the best or worst case so dont mind that
Thanks in advance
ChampSilver
The reason why the worst case run time is O(n) is that if you have a careful look at the code, you realize that you visit each array index at most once:
observe that index i only increases at size, and index j only decrease, therefore you'll go at most once over each index.
For example, if you have an array a[] of size 10, then the initial index i will be 0, and j will be 9. x will be (randlomly) somewhere in between, let's say x=4.
Then, the outer while loop enters, and the first inner while loop increases index i until a[i] >= a[x].
The second inner while loop does the same to index j, for the opposite direction.
But the sum of total iterations of both inner loops is at most 10. At which point the next outer while loop check will return false and no second iteration will occur.
Lets start with this:
our teacher taught us that we have to multiply the costs whenever we have nested statements which would result in a (n/2+1)*((n/2)+1)+((n/2)+1)) which is clearly n^2 and not O(n)
This is only true if the looping variables in inner and outer loops are independent of each other.
eg.
for i in range(1..10):
for j in range(1..10):
do something
This is because, for every value of i, inner loop iterates for all values of j. So, this is O(n^2). Now, lets look the other example:
for i in range(1..10):
for i in range(1..10):
do something
In this case, the outer loop runs only once as when inner loop exits, condition for outer loop also discontinues. So, this is, O(n).
Now, lets look at your while loops.
The outer condition is while i is less than j. Inside, we are always incrementing i and decreasing j. So, in this case, the total number of times while statements (all 3) are executed will be the upper bound on i + j, which is 2n. So, complexity is O(2n) or, O(n).
EDIT:
I am making this edit to explain what "complexity" means, practically.
It is a way of approximating/calculating, number of iterations that are made in total, all loops and instructions combined, as size of input increases. So, if you really want to know that, just assign a variable, say a and add 1 to a as the 1st line of every loop. Then print a for different input sizes and you will know what O() notation means, theoretically vs practically.

java.lang.OutOfMemoryError error in java

I have written a java program in which I am supposed to know that if the two nested for loops can finish their execution in 4 seconds or not If they finish their execution in 4 seconds then the program should continue else break the loop. I have three list A ,B and C and I am performing some operation and adding it to the list B. Even for the small inputs to the list A and C like 3, 6, 8, 4, My program throws run out of memory error
I am using one outer for loop for calculating time. If two for loops couldn't finish their execution in 4 seconds the loop should be terminate. I am using one count variable to keep track of the for loop execution even if for loop finished their execution before 4 seconds i am terminating the outer for loop.
Here is my code :
while(!(A.isEmpty())){
ArrayList<Long> B = new ArrayList<>();
for(long start = System.currentTimeMillis() ; start < System.currentTimeMillis() + 4 * 1000 ; ){
for(long i : A){
for(long j : C){
if(i!=j){
B.add(Math.abs(i-j));
}
}
count++;
if(count==A.size());
break;
}
}
}
What is wrong with this code ? How should I make it correct ?
Thank you.
I think this design isn't really robust. Instead of calling the time function within that loop, I think you could be looking into using two threads here:
Thread A kicks of thread B, and waits for n seconds
Thread B does the computation
When thread A wakes up, it simply checks if the computation is done
Alternatively, your main thread kicks of A and B; and A just comes back and tells you: time to check the results of B now.
And for your real problem; I guess one contributor is here:
B.add(Math.abs(i-j));
You see B (really bad name for a list of numbers btw!) taks Long objects. So that little call there creates at least one Long object per iteration. And you iterate over A and C. Without any sleeps or delays there. This means that your code is doing nothing else but iterating loops and creating new objects to fill that B list.
Now: how many loop iterations do you think you will see in 4 seconds? Enough to create millions and millions of objects?! And then: a dynamically growing list is nice, but you understand what it means when an ArrayList constantly goes over its capacity and needs to grow?! You understand that this means creation of new arrays, and copying around of all values?!
What I am saying is: look carefully how much work is really going on there; and how much (un)boxing of primitive/reference long/Long you got in your code.
One (maybe easy way) to test these ideas: change your code from using List of Longs into using fixed arrays with long values. That will have a nice side effect - it will force you think upfront about how many array slots you actually want to create. In your solution, you just keep looping and adding new objects (as said; leading to constant re-capacity increase operations for your B list).
Statement while(!(A.isEmpty())) will run an infinite loop causing B to be instantiated infinite times.
As a result causing OutOfMemoryError
You Have an infinite loop, while(!(A.isEmpty)) will always be true because inside of your for loops you are never removing any elements from A. This will cause you to add an infinite amount of elements to B becuase of B.add(Math.abs(i-j));

Handling for loop special cases

In Java, C# or C++, suppose we have a very common situation where we need to iterate a large amount of times and execute a function doX, but on only one of the iterations we should execute a function doY.
int index = 123456;
for(int i = 0; i < 1000000; i++)
{
if(i == index) doY();
else doX();
}
In situations where I see a real performance issue, I usually break the loop in 2, but this can be very painful, especially if the loop's body is large. Does the compiled code really check for the condition on every iteration, or can it be optimized by the compiler? Furthermore, if index is not a constant at compile time, can there be such optimizations?
This usually won't cause a huge performance issue. This is due to branch predicting. Refer to this famous question.
Branch predicting is basically assembly's way of guessing which way the if-statement will evaluate to. If it guesses right, it will take almost no time. If it guesses wrong, it will backtrack and cause performance issues. The branch predictor will generally use it's previous branched route as the "guess" for the next branch.
Since your if-statement evaluates to false nearly time. The branch predictor will predict correctly nearly every time.
So to answer your question "Does the compiled code really check for the condition on every iteration?". No it does not. Though it's not optimized by the compiler, but by the assembly pipeline itself.

Finding the computational complexity of a nested loop

I am having a hard time getting the complexity of this for-loop
for (i = 4; i < n; i++)
{
for (j = i - 3, sum = a[i - 4]; j <= i; j++)
{
sum += a[j];
}
System.out.println("sum thru" + i + ": " + sum);
}
I was thinking that the complexity of this nested loop is n^2 since it's a nested loop
but someone told me that this is incorrect and nested loops aren't always a quadratic complexity!
I don't really know how to get the complexity in a good way. I've seen lots of articles about Big-O and complexity but they weren't helpful because they were expecting me to know everything, and they examples weren't the same as any of the examples I have.
I am not asking for the answer, I'm asking for the method. Is there any formula or method that will work for everything in this topic? I want to know how to get the number of assignments but unfortunately I have no clue how to do this.
Can someone explain it to me step by step?
You can see the outer loop iterates (n-4) times, since it is starting with 4 and condition is less than only. The inner loop will iterate maximum of 4 times. Because it starts with i-3 and ends in i. So the complexity is 4*(n-4). Hence the complexity is O(n).
I don't think there is any formula that can solve all problems regarding to time complexity of algorithms. For me, the best way to figure out the big-O is going step by step, from the outer process to the inner process. I believe it is also the standard way for a beginner like you and me. For your question, first, the outer loop is O(n), which is straight forward. Then inside each loop, we have an inner process, which is another loop. That loop goes from i-3 to i, which is O(1). Then inside that process, it is a normal assignment statement, which is O(1) again.
We take all together, the big-O will be O(n) * O(1) * O(1) = O(n)

complexity of code

what is the complexity of a program having only one loop, is it log n?
can someone give me some ideas about estimating complexity of codes?
Well, that really depends on what is going on in that loop.
This loop is linear time, i.e., O(n):
int sum = 0;
foreach( int i in SomeCollection )
{
sum += i;
}
However, consider a loop which performs a substring search during each iteration. Now you have to consider the complexity of the string searching algorithm. Your question can't be answered as it stands. You will need to provide a code sample if you want a meaningful answer.
Software Complexity
There is a field of study that attempts to quantify exactly that.
It's called cyclomatic complexity.
In this case, I believe your complexity rating would be p = 2, because the loop is conditional and that means there are two paths through the method.
Time complexity
If you are referring to time complexity, it's still just O(1) unless the loop iteration count is derived via a polynomial or exponential function, perhaps indirectly because the method is itself called in a higher loop, or because the loop counter is effectively multiplied by string operations or something at a lower level.
To get the Big-O complexity of a piece of code, you need to ask yourself "how many iterations are done"?
The problem is of course, that it isn't always easy to figure it out from the code itself, sometimes it's just better to look at the big picture and calculate the amount of operations done.
Examples:
For (i = 0 ; i < n ; i++ ) {
//Do stuff
}
This is a complexity
For (i = n ; i > 0 ; i= i/2 ) {
//Do stuff
}
This is a complexity... Because in each iteration i is cut in half.
void Mess (int n) {
for (i = 0 ; i < n ; i++) {
//Do stuff
Mess(n-1);
}
}
Now this looks like a simple loop, nut because it calls itself with recursion, it's actually quite a mess.... Each iteration calls itself n times with n-1.
So here it would be easier to think from the end. If n == 1 , there's 1 iteration. If n == 2 then it calls the previous scenario twice.
So if we'll call the function , we can see what we'll get this recursively:
Which in the end will of course give us n!
Bottom line, it's not always trivial.
If there's just one loop, it's probably the number of times that loop's body executes.... But of course you may have many hidden loops in library calls. It's easy to make a loop that executes n times O(n^2) or worse if you have strlen, memcpy, etc. taking place inside the loop body.
Or even worse, if you have a library (or language) with regular expressions and their regex implementation is naive (like Perl), it's easy to make a program with just a single loop O(2^n)!! This cannot happen with a correctly written regex implementation.
You can easily predict the computation time and complexity of your code with some tools such as "trend-prof"(https://pdfs.semanticscholar.org/8616/7f320e230641299754e0fbd860c44f5895f0.pdf)
For the same purpose on R codes, the GuessCompx library available in Github.
If it is Big-O time complexity you are asking about, then for loop it is n times complexity of whatever is within the loop, where n is loop count limit.
So. if the code inside loop is taking constant time to execute, i.e. if its time complexity is O(1), then the complexity of the loop will be O(1*n) = O(n).
In the similar way, if within the loop you have another loop which will make m steps, then your entire code is O(n*m), and so on.

Categories

Resources