Figure 1
Saying $f = O(g)$ is a very loose analog of “$f \le g$.” It differs from the usual notion of $\le$
because of the constant $c$, so that for instance $10n = O(n)$. This constant also allows us to
disregard what happens for small values of $n$. For example, suppose we are choosing between
two algorithms for a particular computational task. One takes $f_1 (n) = n^2$ steps, while the
other takes $f_2(n) = 2n + 20$ steps (Figure 1). Which is better? Well, this depends on the
value of $n$. For $n \le 5$, $f_1$ is smaller; thereafter, $f_2$ is the clear winner. In this case, $f_2$ scales
much better as $n$ grows, and therefore it is superior.
This superiority is captured by the big-O notation: $f_2 = O(f_1)$, because
$$\frac{f_2(n)}{f_1{n}}=\frac{2n+20}{n^2} \le 22$$
or all $n$; on the other hand, $f_1 \neq O(f_2)$, since the ratio $f_1(n)/f_2(n) = n^2/(2n + 20)$ can get
arbitrarily large, and so no constant $c$ will make the definition work.
Now another algorithm comes along, one that uses $f_3 (n) = n + 1$ steps. Is this better
than $f_2$? Certainly, but only by a constant factor. The discrepancy between $f_2$ and $f_3$ is tiny
compared to the huge gap between $f_1$ and $f_2$. In order to stay focused on the big picture, we
treat functions as equivalent if they differ only by multiplicative constants.
Returning to the definition of big-O, we see that $f_2 = O(f_3)$:
$$\frac{f_2(n)}{f_3{n}}=\frac{2n+20}{n+1} \le 20\, ,$$
and of course $f_3 = O(f_2 )$, this time with $c = 1$.
Just as $O(\cdot)$ is an analog of $\le$, we can also define analogs of $\ge$ and $=$ as follows:
$$f = \Omega(g) \text{ means } g = O(f)$$
$$f = \Theta(g) \text{ means } f = O(g) \text{ and } f = \Omega(g) \, .$$
In the preceding example, $f_2 = \Theta(f_3)$ and $f_1 = \Omega(f_3)$.
Big-O notation lets us focus on the big picture. When faced with a complicated function
like $3n^2 + 4n + 5$, we just replace it with $O(f (n))$, where $f (n)$ is as simple as possible. In this
particular example we’d use $O(n^2)$, because the quadratic portion of the sum dominates the
rest. Here are some commonsense rules that help simplify functions by omitting dominated
terms:
- Multiplicative constants can be omitted: $14n^2$ becomes $n^2$.
- $n^a$ dominates $n^b$ if $a > b$: for instance, $n^2$ dominates $n$.
- Any exponential dominates any polynomial: $3^n$ dominates $n^5$ (it even dominates $2^n$).
- Likewise, any polynomial dominates any logarithm: $n$ dominates $(\log n)^3$. This also
means, for example, that $n^2$ dominates $n\log n$.
Don’t misunderstand this cavalier attitude toward constants. Programmers and algorithm
developers are very interested in constants and would gladly stay up nights in order to make
an algorithm run faster by a factor of $2$. But understanding algorithms at the basic level
would be impossible without the simplicity afforded by big-O notation.
Source: Algorithms by Dasgupta, Papadimitriou, Vazirani. McGraw-Hill. 2006.