Big O
algorithm analysis
complexity calculation
performance evaluation
computational efficiency

Big O, how do you calculate/approximate it?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Big O notation is a mathematical concept used in computer science to describe the performance or complexity of an algorithm. Specifically, Big O notation characterizes algorithms based on how their run time or space requirements grow as the input size increases. The Big O notation provides an upper bound on time or space complexity, allowing engineers and computer scientists to understand and compare the efficiency of different algorithms.

Understanding Big O Notation

Big O notation simplifies complex algorithmic performance equations by bounding the function in the worst-case scenario. The notation O(f(n))O(f(n)) implies that the growth rate of function T(n) is no more than a constant factor of the function f(n) for large n.

Technical Definitions

  • T(n): Represents the time complexity function that describes the actual execution time in real terms based on the input size n.
  • f(n): Represents the simplified function to provide an upper bound.

The relationship is formally defined as:

T(n) = O(f(n)) means there is a constant c > 0 and a threshold n0 >= 0 such that T(n) <= c * f(n) for all n >= n0.

Common Big O Notations:

  • O(1)O(1): Constant time
  • O(logn)O(log n): Logarithmic time
  • O(n)O(n): Linear time
  • O(nlogn)O(n log n): Linearithmic time
  • O(n2)O(n^2): Quadratic time
  • O(n3)O(n^3): Cubic time
  • O(2n)O(2^n): Exponential time
  • O(n!)O(n!): Factorial time

Calculating Big O

Determining the Big O of an algorithm involves analyzing its steps within loops, recursive operations, or any iterative process. Here are some steps and examples to help approximate Big O:

Analyzing Loops

  1. Simple Loops:
python
   for i in range(n):
       # constant time operation

Each iteration executes a constant time operation, resulting in O(n)O(n).

  1. Nested Loops:
python
   for i in range(n):
       for j in range(n):
           # constant time operation

The outer loop runs n times, and the inner loop runs n times for each iteration of the outer loop. This results in O(n2)O(n^2).

Analyzing Recursive Calls

Recursion can lead to complex performance characteristics. For instance, a common recursion relation such as binary search outlines a logarithmic pattern:

python
1def binary_search(arr, target, low, high):
2    if high >= low:
3        mid = (high + low) // 2
4        if arr[mid] == target:
5            return mid
6        elif arr[mid] > target:
7            return binary_search(arr, target, low, mid - 1)
8        else:
9            return binary_search(arr, target, mid + 1, high)
10    else:
11        return -1

Given the recursion halves on each step, this results in a time complexity of O(logn)O(log n).

Best, Worst, and Average Case

Big O typically describes the worst-case scenario, but it's essential to consider:

  • Best Case: Minimum time required. For example, searching for an element at the beginning of a list is O(1)O(1).
  • Average Case: Average time required over all input conditions.
  • Worst Case: Maximum time required over all inputs. Key for performance guarantees.

Summary Table

Complexity ClassDescriptionExample
O(1)O(1)Constant timeAccessing a specific index in an array
O(logn)O(log n)Logarithmic time (divide in pieces)Binary search
O(n)O(n)Linear timeSingle loop through an array
O(nlogn)O(n log n)Linearithmic time (efficient sorts)Merge sort, quick sort (average)
O(n2)O(n^2)Quadratic time (nested loops)Bubble sort, selection sort
O(2n)O(2^n)Exponential time (recursive)Fibonacci sequence (naive)
O(n!)O(n!)Factorial timeTraveling salesman grid search

Additional Considerations

  1. Space Complexity: Similarly to time complexity, space can also be bounded by Big O notation.
  2. Amortized Analysis: Sometimes, average over multiple operations may provide a clearer picture of an algorithm's efficiency.
  3. Tight Bounds: While Big O gives the upper bound, Θ(n)\Theta(n) can provide a tight bound for both upper and lower bounds.

Understanding Big O notation and its accurate assessment are fundamental in crafting efficient algorithms, allowing for the clear communication of performance constraints and capabilities.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.