Big-O Notation

Understanding relative representation of the complexity of an algorithm.

What is Big O?

  • Big O notation is used to describe the performance or complexity of an algorithm.
  • Big O specifically describes the worst-case scenario.
  • Used to describe the execution time required or the space used by an algorithm.

Big O complexity can be visualized with this graph

Algorithm's Scale as follows...

*listed in order of complexity

O(1)

  • O(1) describes an algorithm that will always execute in the same time regardless of the size of the input data set.

constant complexity

// For example, accessing any single element in an array takes 
// constant time as only one operation has to be performed to locate it.

const arr = [ 'accessing', 'an', 'array', 'element', 'takes', 'constant', 'time']
const index = arr[4] // return 'takes'

O(N)

  • O(N) describes an algorithm whose performance will grow linearly and in direct proportion to the size of the input data set.

Linear complexity

// For example, a procedure that 
// adds up all elements 
// of a list requires time 
// proportional to the length of the list.

const start = new Date().getTime();

const arr = []
let j = 0;

while ( j < 100000 ) {
    arr.push(j);
    j++;
}

let sum = 0;

for ( let i = 0; i < arr.length; i++ ) {
    sum += arr100[i];
}

const end = new Date().getTime();
const time = end - start;
console.log('Execution time: ' + time);

O(     )

  • O(     ) represents an algorithm whose performance is directly proportional to the square of the size of the input data set.

quadratic time

// This is common with algorithms 
// that involve nested iterations 
// over the data set. Deeper nested 
// iterations will result in O(N3), O(N4) etc.

const grid = document.createElement('table');
grid.className = 'grid';

for (let r = 0; r < this._rows; ++r) {
  const tr = grid.appendChild(document.createElement('tr'));

  for (let c = 0; c < this._cols; ++c) {
    const cell = tr.appendChild(document.createElement('td'));
    cell.id = "grid" + i++
  }
}
N^2
N^2

O(     )

  • O(     ) The growth curve of an O(     ) function is exponential - starting off very shallow, then rising meteorically.

exponential time

// An example of this is trying to break a password by testing 
// every possible combination (assuming numerical 
// password of length N). This results in O(10^N) complexity.
2^N
2^N
2^N

O( log N )

  • Algorithms taking logarithmic time are commonly found in operations on binary trees or when using binary search.
  • An O(log n) algorithm is considered highly efficient, as the operations per instance required to complete decrease with each instance.

logarithmic time

O( log N )

Continued...

// An example of logarithmic algorithm is an algorithm that cuts 
// a string in half, then cuts the right half in half, and so on. It will take 
// O(log n) time (n being the length of the string) since we chop the string 
// in half before each print

// Function to recursively print the right half of a string
const right = function(str) {
    const length = str.length;
    
    // Helper function
    const help = function(index){
        
        // Recursive Case: Print right half
        if (index < length){
          
            // Prints characters from index until the end of the array
            console.log(str.substring(index, length));
            
            // Recursive Call: call help on right half
            help(Math.ceil((length + index) / 2));
        }
        
        // Base Case: Do Nothing
    }
    help(0);
}

Resources

Big-O

By DevLeague Coding Bootcamp

Big-O

Understanding relative representation of the complexity of an algorithm.

  • 1,888