If I have an algorithm that takes 4n^2 + 7n moves to accomplish, what is its O? O(4n^2)? O(n^2)?
I know that 7n is cut off, but I don\'t know if I should keep the n^2 c
Everyone reading or writing about complexity of algorithms should know exactly what the Landau Symbols and asymptotic notations are, otherwise they don't really understand what is going on, or simply have an approximate (and often misleading) idea.
To simplify (a lot), let f
and g
be two functions f : N -> N
and g : N -> N
. We say that f is O(g)
if and only if there's a constant M > 0
such that |f(n)| < M|g(n)|
, for all n > M
. That is, more informally, starting from a big value of n
, all the values f(n)
are smaller than a multiple of g(n)
(ie, g
grows faster than f
).
That definition is equivalent to
f is O(g) <==> There is K >= 0 such that lim{n -> +oo} |f(n)|/|g(n)| = K
So, let's take f(n) = 4n^2 + 7n
and g(n) = n^2
, and try to prove f is O(g)
(I will omit {n -> +oo}
):
lim |f(n)|/|g(n)| = lim f(n)/g(n) = lim (4n^2 + 7n) / n^2 = 4 + lim 7n/n^2 =
= 4 + lim 7/n = 4 + 0 = 4
This implies that there is a M
such that n > M ==> |f(n)| < M|g(n)|
, and thus f is O(g)
.
So technically it is correct to say 4n^2 + 7n is O(4n^2)
, as it is correct to say 4n^2 + 7n is O(n^3)
, 4n^2 + 7n is O(e^n)
, and so on. But to be meaningful, we are interested in the lower bound. So if f is O(e^n)
and f is O(n^2)
, we are more interested into knowing that f is O(n^2)
, since this is much more restrictive.
What is extremelly important when choosing an algorithm is to understand that big-O notations refers to asymptotic cases, that is, when you consider extremely, unimaginable huge inputs, that can go well beyond the computational power available in the known universe (ie, infinite input sets, expressed mathematically by {n -> +oo}
).
For practical uses (ie, not so huge inputs), when choosing an algorithm, sure, you will observe candidate algorithms big-O notations, but you must be sure that the chosen algorithm is well adapted (and performs better) for your (expected) input.
Finally, usually better performing algorithms are more difficult to understand and to implement properly. You must consider this fact as well when choosing an algorithm (ie, is the time I will spend debugging and fixing my implementation of this algorithm considerably superior to the time I would have to wait with another algorithm, with a worse big-O notation?. If so, you should consider the simpler, less efficient algorithm, as the overall solution would be more efficient).