Purpose
Running time is roughly proportional to the number of simple operations performed, so counting operations as a function of input size is how we compare algorithms without benchmarking them. This note pins down the three asymptotic notations and the growth-rate facts worth memorizing.
O-Notation
Given two functions and , we say that is if there exist constants and such that for all .
Omega-Notation
Given two functions and , we say that is if there exist constants and such that for all .
Theta-Notation
Given two functions and , we say that is if there exist constants , , and such that for all .
The three bounds
Notation Role Guarantee for all upper bound lower bound tight bound both, with separate constants
Common Bounds
Logarithms grow slower than every polynomial with , and every polynomial grows slower than every exponential with .
Polynomial
Logarithmic
Base changes only shift a logarithm by a constant factor, since .
Exponential
Factorial
”Efficient” Algorithms
A single CPU core executes on the order of simple operations per second. That budget makes exponential algorithms useless beyond tiny inputs: operations is decades of compute, and blows past that at .
Polynomial time is the standard bar for an efficient algorithm, and it has a useful scaling property: if the input size grows by a constant factor, the running time of a polynomial time algorithm also grows by a constant factor.