Does "&&" in an if statement affects the time complexity? - performance

Let's just say if there was an if statement like
if(arraylist.indexOf(n) < 14 && arraylist.indexof(m) < 20) {
doSomething();
}
Would the if statement be O(n) or O(n^2)? The time complexity of indexOf(n) is O(n). I tried searching the answer on google but can't seem to find it.

You don't have a language tag here, but I'll assume it supports short-circuiting (most do).
The complexity with be whatever arraylist.indexOf is times 2. So, if you're correct and the complexity is O(n), the complexity of your if (assuming no short-circuiting) is O(2n) (and since you'll typically simplify complexity by dropping constants, O(n)).

It is not unreasonable to be worried about hidden performance implications of a using O(N) function. However, in this case, there is not additional penalty. Worst case occurs when the indexOf is called for both sides of the &&. The time complexity does not change in this case, since the O(N) is applied at most twice.
I have encountered hidden complexity issues in using concatenation functions, where the concatenation requires traversal of the original value before appending the additional data (e.g., C's strcat). A caller that is unaware of the traversal is occurring may write a loop that performs the concatenation on each iteration, not knowing this is triggering an order of magnitude increase in time complexity.

Related

What is complexity of O(1/n) compared to O(n)?

Is O(1/n) faster growing than O(1)? I am studying time complexity and saw O(1/n) being compared to O(n) as one of my exercise questions, and I had never seen that before. Not sure how to deduce the answer to this question.
A complexity of O(1/n) would means that the more data you process, the faster is the algorithm... Quite difficult to believe, for first, and second let's do maths: the limit of 1/x when x goes to +INF is zero...
The algorithm would resolve instantly the problem, then? Hey, let's forget about quantum computing, we found something better! :)
Stop joking: such a complexity doesn't exist. Because 1/n is a decreasing monotonic function. Complexities are increasing monotonic functions - at best, it's O(1), meaning a constant time whatever the data quantity is. It's not even a so common complexity for an algorithm, in fact, even if it's quite frequent for certain operations / manipulations.
For example, retrieving the head of a standard linked list is indeed O(1), even if the list is empty or if it contains all possible data of Universe (if it was storable...), because list's head is what is stored to access it. It's the same for all operations involving only exchanging pointers/handles exclusively, all direct accesses (like the [] operator of most arrays), etc. but most algorithms don't have such a nice complexity.
But even a simple (deep) copy is O(n)... Most researchs in a storage are in O(log2(n)). Most sorts are in O(n.log2(n)). Most cross-comparisons are in O(n²). All these functions are (strictly) increasing. All these functions tend to infinity when n also tends to infinity.

How do i measure the O-notation of a for loop?

i have a question about O-notation. (big O)
In my code, i am using a for loop to iterate through an array of users.
The for loop has if-statements that makes it break out of the loop, if the rigth user is found.
My question is how i measure the O-notation?
Is the O-notation is O(N) as i loop through all the users in the array?
Or is the O-notation O(1), as the loop breaks and never runs again?
O notation defines an "order of" relationship between an amount of work (however measured) and the number of items processed (usually 'n'). So "O(n)" means "in direct proportion to the number of items n". "O(1)" means simply "constant". If a loop processes every item once then the amount of work is intuitively in direct proportion to n, but let's say that your exit condition gets hit on average half way through, we might be tempted to say that this is O(n/2), but instead we still say that it is O(n) because the relationship to n is still direct/linear. Similarly if you were to assess the relationship to be O(7n^3 + 2n), you'd say the relationship was simply O(n^3) because n^3 is the term that dominates as n grows large.
The answer to your specific question is therefore O(n) because the number of iterations is in direct proportion to n. All that this says is that if N user records take M milliseconds to process, 2N should take about 2M milliseconds.
It is probably worth noting that O notation is strictly concerned with worst case and not the average cost of algorithms (although I have started to find that it is quite common for people to use it in the latter sense). It is always a good idea to specify to avoid ambiguity.
Big O notation answers the following two questions:
If there are N data elements, how many steps will the algorithm take?
How will the performance of the algorithm change if the number of data elements increases?
Best-case scenario in your case is that the user you are searching for is found at the first index. Time complexity in this case would be O(1) because number of steps taken by the algorithm are constant and do not change if the number of elements in the array are changed.
The worst-case scenario is that your loop will have to iterate over all the users. That makes the time complexity to be O(N) because number of steps taken by the algorithm will be directly proportional to the number of elements in the array.
Big O notation generally refers to the worst-case scenario, so you can say that the time complexity in your case is O(N).
Best case complexity of for loop is O(1) and worst case complexity is O(N). In linear search best case is O(N) and worst case is O(N). It also depends on the approach followed by you to solve problem. Like for(int i = n; i>1; i=i/2) in this case complexity is O(log(N). Complexity of if else condition is O(1).

Do Nested If Statements within Foreach loops add to Computation Complexity more than just linearly?

I've started to run static code analysis on my solution and noticed my team has a section with a "code complexity" rating off the charts.
I looked into it and found 15 levels of nested if statements, with a foreach loop on the outside, and 2 nest levels within.
I'm familiar with big O notation and the complexity of a dictionary lookup compared to a double for (foreach) loop turning into a polynomial increase of inefficiency as opposed to a linear increase.
However, does that mean that the if statements are causing any real further complexity?
Or is the issue really just the foreach within another foreach and the if statements are just a linear increase like as a bunch of case statements with fall through?
IE: is just more of a readability/maintainability issue than an actual effiiciency issue?
I realize that this is a sign of there likely being a better algorithm to handle what is being done here, but I'm looking for a mathematical understanding of the inefficiency from the if statements within the foreach statements if there is one.
You might be looking at Cyclomatic Complexity. There many be an large amount of paths your code can partake because of the number of if statements. Imagine a Tree with roots reaching down and every if statement is a split in the roots where they branch in different directions.
There would be a lot of individual root paths!
Cyclomatic complexity is a software metric, used to indicate the complexity of a program. It is a quantitative measure of the number of linearly independent paths through a program's source code.
A way to decrease the Cyclomatic complexity is to eliminate the number of unique paths if possible.
The nested IF statements may be adding Time Complexity.
First of all, having nested for-loops will cause a O(N^2) time complexity.It really depends what is the nature of those if statements. If the if statements are O(1) such as checking if a variable is equal to a int, it should have almost no impact to your runtime.
for(Object1: Array1){
for(Object2: Array2){
if(Object1.number == 20){
if(Object2.number = 10){
...
}
}
}
}
O(N^2) Time Complexity
However if those if statements are iterating over a collection to find a match, it will add an additional layer of O(N) complexity for each collection iteration.
for(Object1: Array1){
for(Object2: Array2){
if(Array3.contains(Object1)){
if(Array4.contains(Object2)){
...
}
}
}
}
O(N^4) or more Time Complexity
It is important to see what the time complexity of each if statement is. It is even possible that each if statement is worse than O(N) which would negatively impact the performance of your program.

Does every algorithm has a best case data input?

Does every algorithm has a 'best case' and 'worst case' , this was a question raised by someone who answered it with no ! I thought that every algorithm has a case depending on its input so that one algorithm finds that a particular set of input are the best case but other algorithms consider it the worst case.
so which answer is correct and if there are algorithms that doesn't have a best case can you give an example ?
Thank You :)
No, not every algorithm has a best and worst case. An example of that is the linear search to find the max/min element in an unsorted array: it always checks all items in the array no matter what. It's time complexity is therefore Theta(N) and it's independent of the particular input.
Best Case input is the casein which your code would take the least number of procedure calls. eg. You have an if in your code and in that, you iterate for every element and no such functionality in else part. So, any input in which the code does not enter if block will be the best case input and conversely, any input in which code enters this if will be worst case for this algorithm.
If, for any algorithm, branching or recursion or looping causes a difference in complexity factor for that algorithm, it will have a possible best case or possible worst case scenario. Otherwise, you can say that it does not or that it has similar complexity for best case or worst case.
Talking about sorting algorithms, lets take example of merge and quick sorts. (I believe you know them well, and their complexities for that matter).
In merge sort every time, array is divided into two equal parts thus taking log n factor in splitting while in recombining, it takes O(n) time (for every split, of course). So, total complexity is always O(n log n) and it does not depend on the input. So, you can either say merge sort has no best/worst case conditions or its complexity is same for best/worst cases.
On the other hand, if quick sort (not randomized, pivot always the 1st element) is given a random input, it will always divide the array in two parts, (may or may not be equal, doesn't matter) and if it does this, log factor of its complexity comes into picture (though base won't always be 2). But, if the input is sorted already (ascending or descending) it will always split it into 1 element + rest of array, so will take n-1 iterations to split the array, which changes its O(log n) factor to O(n) thereby changing complexity to O(n^2). So, quick sort will have best and worst cases with different time complexities.
Well, I believe every algorithm has a best and worst case though there's no guarantee that they will differ. For example, the algorithm to return the first element in an array has an O(1) best, worst and average case.
Contrived, I know, but what I'm saying is that it depends entirely on the algorithm what their best and worst cases are, but the cases will exist, even if they're the same, or unbounded at the top end.
I think its reasonable to say that most algorithms have a best and a worst case. If you think about algorithms in terms of Asymptotic Analysis you can say that a O(n) search algorithm will perform worse than a O(log n) algorithm. However if you provide the O(n) algorithm with data where the search item is early on in the data set and the O(log n) algorithm with data where the search item is in the last node to be found the O(n) will perform faster than the O(log n).
However an algorithm that has to examine each of the inputs every time such as an Average algorithm won't have a best/worst as the processing time would be the same no matter the data.
If you are unfamiliar with Asymptotic Analysis (AKA big O) I suggest you learn about it to get a better understanding of what you are asking.

Is best Big O Time efficiency always the same as best Space efficiency for recursive solutions?

If a recursive solution ends up calling itself consecutively for say, ~N times, before going back up a level, the space efficiency is O(N) at best, because each of the N calls uses up a certain amount of stack space.
Does this also imply the time efficiency is also O(N) at best, because the code inside the recursive function is similar to an inner loop code that gets run ~N times?
In addition to #Ben's answer there is also the case of "tail recursion" where the current stack frame is removed and replaced by the callee's stack frame, but only when the caller's last action is to return the result of a callee. This can result in O(n) time functions having O(1) space when implemented in an entirely functional language.
No, but your observation has some truth in it - basically if you know that any algorithm (recursive or otherwise, since we don't distinguish the two; and there isn't anything really that could distinguish them, it's more a matter of style) for a given problem has space complexity at least f(n), it must have time complexity at least f(n), too.
No, since each step of the recursive algorithm can take longer than O(1). If each step take O(n) then the total time complexity is O(n^2).

Resources