The Big-O Notation

Have a look at the runtime of different algorithms.

To figure out how long a program would take to run on a real computer, we would need to know things like the speed of the computer, the system architecture, the compiler being used, details of the memory hierarchy, and so on. Therefore, carefully estimating the running time is a rather difficult task. Moreover, in practice, we might not even know some of these details. That is why computer scientists use the big-OO notation to estimate the running time of an algorithm without knowing anything about all these details!

Big-OO notation: Comparing running times

Consider two algorithms and denote by f(n)f(n) and g(n)g(n) their running times on an input of size nn. We say that ff grows no faster than gg, if there exists a constant cc such that for every positive integer nn, f(n)cg(n)f(n)\leq c\cdot g(n) (equivalently, f(n)g(n)c\frac{\text{f(n)}}{\text{g(n)}} \leq c). In this case, we write f=O(g)f = O(g) or fgf \preceq g. The notation f=O(g)f = O(g) is a standard one, whereas some learners find the notation fgf \preceq g to be more intuitive.

To give an example, let f(n)=4nlog2nf(n) = 4n\log_{2}{n} and g(n)=n2g(n) = n^2. To visualize the order of growth of the two considered functions, let’s plot them for 1n301 \leq n \leq 30. Here is a simple Python code for generating this plot that you can use as a template for plotting any other functions.

Click the “Run” button below to generate a graph.

Press + to interact
import matplotlib.pyplot as plt
import numpy as np
n = np.linspace(1, 30)
plt.plot(n, 4 * n * np.log2(n), label='$4n\log_2(n)$')
plt.plot(n, n ** 2, label='$n^2$')
plt.legend()
plt.savefig('output/to.png')

As the picture reveals, 4nlog2nn24n\log_{2}n\geq n^2 for n16n\leq16, but then the two functions switch. Indeed, 4nlog2nn4n\log_{2}n\geq n for n16n\geq16. In particular,

4nlog2n16n24n\log_{2}n\leq 16n^2 for all n1n\geq1.

We conclude that 4nlog2n=O(n2)4n\log_{2}n=O(n^2).

Now, let f(n)=2n2+5n+3f(n)=2n^2+5n+3 and g(n)=n2g(n)=n^2. On one hand, f(n)f(n) is larger than g(n)g(n) for all positive nn. On the other hand,

f(n)=2n2+5n+32n2+5n2+3n2=10n2=10g(n)f(n)=2n^2+5n+3 \leq 2n^2+5n^2+3n^2=10n^2=10g(n)

for all positive integers nn. That is, f(n)f(n) is at most ten times larger than g(n)g(n). We conclude that ff grows no faster than gg ((and write f=O(g)f=O(g) or fg)f\preceq g).

Click the “Run” button below to generate a graph.

Press + to interact
import matplotlib.pyplot as plt
import numpy as np
n = np.linspace(1, 100)
plt.plot(n, 2 * n ** 2 + 5 * n + 3, label='$2n^2+5n+3$')
plt.plot(n, n ** 2, label='$n^2$')
plt.plot(n, 10 * n ** 2, label='$10n^2$')
plt.legend(loc='upper left')
plt.savefig('output/to.png')

We can also plot the fraction f(n)g(n)\frac{f(n)}{g(n)}. Run the code below to generate a graph.

Press + to interact
import matplotlib.pyplot as plt
import numpy as np
n = np.linspace(1, 100)
plt.plot(n, (2 * n ** 2 + 5 * n + 3) / (n ** 2))
plt.savefig('output/to.png')

This plot shows that (at least, in the considered range 1n1001\leq n\leq 100) the fraction f(n)g(n)\frac{f(n)}{g(n)} is at most 1010 and, in fact, approaches 22 as nn grows.

Now, let’s compare f(n)=11nf(n)=11n and g(n)=2n2+5n+3g(n)=2n^2+5n+3. First, let’s look at their plots. Click the “Run” button below to generate a graph.

Press + to interact
import matplotlib.pyplot as plt
import numpy as np
n = np.linspace(1, 100)
plt.plot(n, 11 * n, label='$11n$')
plt.plot(n, 2 * n ** 2 + 5 * n + 3, label='$2n^2+5n+3$')
plt.legend()
plt.savefig('output/to.png')

We notice that both functions grow (as nn grows) but 11n11n grows slower. This can be made formal as follows.

For two functions, f,gf, g we say that ff grows slower than gg and write f=o(g)f = o(g) or fgf\prec g, if the fraction f(n)g(n)\frac{f(n)}{g(n)} goes to zero as nn grows.

Exercise break: Plot the fraction 11n2n2+5n+3\frac{11n}{2n^2+5n+3} to ensure that it goes to zero as nn grows.

Of course, if fgf\prec g (equivalently, f=o(g)f=o(g)), then also fgf\preceq g (equivalently, f=O(g)f=O(g)). In plain English: if ff grows slower than gg, then certainly ff grows no faster than gg.