DEV Community

Discussion on: A coffee-break introduction to time complexity of algorithms

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

Your article has a few common misunderstandings about what BigO is measuring.

The statement, "Big O notation gives us our algorithm's approximate run time in the worst case", is not true, not even in it's common use in programming. If it were, then a HashMap insertion would be O(n^2) instead of the commonly quoted O(1), which results from measuring an average complexity over a good data set, not the worst case. Similarly, adding an item to a vector is often quoted as O(1), which is it's amortized time, the worst-time being O(n).

It's often misused in programming to mean a tight bound, when it is actually an upper-bound. A simple for-loop can be O(n), but O(n^3) is technically also an upper bound for it. There's a related Ω for lower-bound, and Θ for a tight bound. When we measure an algorithm we typically want the Θ, not O, but this is commonly misused, probably just because we don't have Θ on our keyboards. Big-Oh is a good way to specify a limit, whereas Θ is a good way to measure it.

Your initial diners solution is O(n), not O(n^2). Adding a constant loop, like the 0..3 in this case, does not alter the complexity. That would be 3*N which simplifies to O(n). That is, ignoring the slice and append, which have an unknown complexity here.

Collapse
 
victoria profile image
Victoria Drake

Thank you for the response!

You're right that the way the term Big O is used in an informal context isn't completely mathematically correct. As I was writing this article, I had a lengthy discussion with someone who has an advanced mathematics background. We discussed the differences between upper and tight bounds, and amortized and worst-case complexities specifically. Ultimately, the goal of this article is to present the concepts of time complexity in a way that programmers would encounter in practical, daily terms. In terms of the wording, see the Wikipedia entry for Big O notation, which states:

"For example, if T(n) represents the running time of a newly developed algorithm for input size n, the inventors and users of the algorithm might be more inclined to put an upper asymptotic bound on how long it will take to run without making an explicit statement about the lower asymptotic bound."

Ultimately, in practical use, the colloquial "misuse" of Big O suffices. I found that going farther into asymptotic analysis in this article was not helpful from a pragmatic standpoint.

I probably should have mentioned in the article that these things were considered, but not included, so thank you for the feedback! I'll make better note of those things in the future.

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

I understand that the casual use in coding is is different than math, but saying that is the "worst case" is also wrong for common coding.

We tend to consider hash maps O(1), vector add as O(1), map insert as O(log N), quicksort as O(N * log N), but none of those are true in the "worst case". We use average input case, typical case and amortized case on a regular basis, likely more common than worst-case when it comes to collections and common algorithms.

Collapse
 
nestedsoftware profile image
Nested Software • Edited

It is not my domain of expertise, but assuming I am not wrong, maybe it's worth adding something like this: Big O measures the upper bound on a function. Big O can, but does not necessarily, refer to the running time in the worst case. We can determine Big O for various scenarios, including the best case, worst case, typical case, etc.

Update: I re-read the part of the sentence about this in the article:

Big O notation gives us our algorithm's approximate run time in the worst case, or in other words, its upper bound

I think @vickylai meant that the function would not have worse performance than the given upper bound, so it was a "worst case" in that sense.

However the input was not specified. For example, if we have a (contrived) function that is O( n2 ) for any even number as input, but O( n ) for odd-numbered input, the "worst case" in that sense is when it receives an even number and the "best case" is if receives an odd number.

The use of the term "worst case" refers to two different things in each of the two paragraphs above.

It doesn't always make a difference, but in practice we can't study the big O of any algorithm without some context around input. It's worth keeping that in mind.