A Quick Primer On Big O Notation
By: Maxwell Harvey Croy
Tags: Software Engineering, Algorithms, Programming

First, let’s be clear about what Big O isn’t. Big O is not going to give you or your team an exact answer on how long a piece of code will take to run. Far from it. As I mentioned earlier, Big O allows us to discuss our code algebraically to get a sense of how quickly it might operate under the strain of large data sets. Luckily, this simplifies things a bit for us newcomers, as it allows us to move our focus from runtime in terms of milliseconds to discussing runtime in relation to the number, and complexity, of operations in our code.

For example, let’s say we have the following piece of code:

def example_search(key, array)

for i in 0...array.length

return "#{key} found!" unless array[i] != key

end

return "#{key} not found :("

end

Here, we’re merely looping through a provided array to find a specific key. If that key isn’t found, we’re sure to highlight that as well. It’s a pretty quick operation overall if we’re using an array with five items, but what if we use this method to search for a key in an array 1,000 items long, or even 100,000 items long?

Well, with Big O Notation, we can look at our algorithm and see that it will take O(n) time to run. Big O Notation, written as O(blank), show us how many operations our code will run, and how its runtime grows in comparison to other possible solutions.

Our example code runs at O(n) because in the worst-case if our key isn’t found the first time our code runs, it might have to continue looping through the entire array until we can determine if the key is there or not and its runtime will continue growing at a constant rate.

Why did I emphasize worst-case? We always want to focus on the maximum amount of time a process could take to understand the outer limits of our code to avoid bad solutions. It reassures us that a solution won’t take longer than we expect, and empowers us to feel confident that our code won’t lead to runtime issues in the future.

So how does a runtime of O(n) compare to other run times, and what other runtimes can we expect for different types of solutions? Well, every algorithm is going to have its own runtime, but you can expect to see the following run fairly commonly:

O(log n)

O(n)

O(n * log n)

O(n²)

O(n!)

For now, don’t worry about how to calculate these yet (we’re just taking baby steps for the moment). All you need to know for now is that the list above is ordered by efficiency — algorithms that run at O(log n) run much faster than algorithms that run at O(n!). You can find a graph demonstrating this below:

Graph of Possible Runtimes (source: https://bit.ly/31XKRXO)

Ultimately, this is a simplification, and things are rarely so neat. But, with practice and further research, you’ll begin to develop a better understanding of how Big O run time can be determined for specific algorithms, and how they compare to other possible solutions.

Conclusion

And that’s it — a quick primer on what Big O Notation, and why it is so essential for Software Engineers. If you only remember a few things from this article, it should be these:

Algorithm speed isn’t discussed in actual runtime but Big O Notation.

Big O Notation is important because it allows us to discuss the efficiency of our code and compare solutions without getting caught up in complex calculations.

We always focus on the worst-case when using Big O Notation to ensure that we choose the most efficient solution at scale.

Scale influences speed significantly, and even though an O(n) solution might be faster than an O(log n) solution at first, that changes quickly as you add more data to the equation.

Hopefully, you walk away from this article feeling empowered to tackle this subject on your own. As I mentioned earlier, Big O Notation and Space & Time Complexity are subjects that truly essential for Software Engineering, and your understanding of them could be what leads you to land your dream job.

Good luck!