This repository is a developer diary that I will use as I'm reading the Grokking Algorithms: An Illustrated Guide for Programmers and Other Curious People book and studing data structures, I will add examples for each part of it with javascript examples
- Big O (Work in Progress)
- Bubble Sort (TO DO)
- Selection Sort (TO DO)
- Insertion Sort (TO DO)
- Merge Sort (TO DO)
- Quick Sort (TO DO)
- Radix Sort (TO DO)
- Linked List (TO DO)
- Stack & Queue (TO DO)
- Binary Tree (TO DO)
- Binary Heap (TO DO)
- Hash Table (TO DO)
- Graph (TO DO)
We needed a way of measuring our algorithms complexity, if we have multiple solutions for the same problem which one is the best(requires lesser operations to run)?
Big O notation establishes a way of measuring the complexity of our algorithms, particularly their time and space requirements, in relation to the size of their input. These notations can be one of the following:
- Constant - O(1)
- Linear - O(n)
- Quadratic - O(n²)
- Logarithmic - O(log n)
- Linearithmic - O(n log n)
- Polynomial - O(n^c)
- Exponential - O(2^n)
- Factorial - O(n!)
Time complexity pertains to the fluctuations in an algorithm's execution time as the input size escalates. To classify an algorithm, we scrutinize the interplay of inputs and operations, identifying whether the algorithm adheres to a constant, linear, quadratic, logarithmic, linearithmic, exponential or factorial growth pattern. This analysis sheds light on an algorithm's scalability and efficiency traits by revealing how it responds to varying input sizes.
Changing the input won't change the numbers of operations
example:
function isEven(n) {
return n % 2 === 0;
};
Every time we change
n
the number of operations still the same (the remainer(%) and the indentity(===) are the operations)
Changing the input the number of operations grows equality to it
example:
function countUntil(n) {
for(let i = 0; i <= n; i++) {
console.log(n);
};
}
Every time we change
n
the number of operations grows equal to it, here we have 3 operations the asignment(i = 0) the less equal then(i <= n) and the increment(i++) so ifn
is 1 we have 3 operations but ifn
is 5 we have 11(1+5x2) operations because the less equal then and the increment will run N times
Changing the input the number of operations grows quadratic to it
example:
function printPairs(n) {
for(let i = 0; i <= n; i++) {
for(let y = n; y > i; y--) {
console.log(i, y);
};
};
}
Here every time we change
n
the number of operations grow quadratic to it, we got 6 operations (i = 0, i <= n, i++, y = n, y > i and y--) but for everyi
we gotn
times ofy
operations so ifn
is 1 we have 6 operations, but ifn
is 5 we got 111(1+5x2(1+5x2)) operations
- Arithmetic operations are constants
- Variable assignment is constant
- Acessing elements in a array by index or object is constant
- In a loop the complexity is the length of the loop times the complexity of what is inside it
Space complexity pertains to the evolving memory allocation of an algorithm as the input size changes. Just as we categorize algorithms for time complexity, we assess the connection between inputs and memory allocations. This process helps us determine whether an algorithm follows a constant, linear, quadratic, logarithmic, linearithmic, polynomial, exponential or factorial growth pattern in terms of memory usage. This evaluation uncovers the ways an algorithm's memory needs transform with differing input scales, offering valuable insights into its scalability and memory efficiency characteristics.
Changing the input won't change the numbers of memory allocation
example:
function isEven(n) {
const isEven = n % 2 === 0;
return isEven;
};
Every time we change
n
the number of assignments still the same (the const isEven = n % 2 === 0)
Changing the input the number of assignments grows equality to it
example:
function populateArrayWith(n) {
const arr = [];
for(let i = 0; i <= n; i++) {
arr.push(i);
};
console.log(arr);
}
Every time we change
n
the length of the array grows equal to it, here for every for loop we push a new elementi
to the array
Changing the input the length of the matrix grows quadratic to it
example:
function createMatrix(n) {
const matrix = [];
for (let i = 0; i < n; i++) {
const row = [];
for (let j = 0; j < n; j++) {
row.push(i + j);
}
matrix.push(row);
}
return matrix;
}
Here every time we change
n
the memory allocation grow quadratic to it, in the first for loop for everyi
we create a matrix row and inside it we have another for loop for everyj
we pushi+j
to the row and after that push the row to the matrix
- Primitives values (boolean, number, undefined, null) are constant space
- Strings require O(n) space where n is the string length
- Arrays and Object require O(n) space where n is the size of the array or the number of keys in the object