├── .gitignore ├── README.md ├── package-lock.json ├── package.json └── src ├── benchmark.js ├── bogo.js ├── bubble.js ├── cocktail.js ├── gnome.js ├── heap.js ├── insertion.js ├── jssort.js ├── merge.js ├── quick.js ├── radix.js ├── selection.js └── shell.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sorting Algorithms in JavaScript 2 | 3 | 10 Sorting algorithms implemented in JavaScript. 4 | 5 | - [Sorting Algorithms Video Tutorial](https://youtu.be/RfXt_qHDEPw) 6 | - [15 Sorting Algorithms](https://youtu.be/kPRA0W1kECg) -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sort", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "sort", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "chance": "^1.1.9" 13 | } 14 | }, 15 | "node_modules/chance": { 16 | "version": "1.1.9", 17 | "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.9.tgz", 18 | "integrity": "sha512-TfxnA/DcZXRTA4OekA2zL9GH8qscbbl6X0ZqU4tXhGveVY/mXWvEQLt5GwZcYXTEyEFflVtj+pG8nc8EwSm1RQ==" 19 | } 20 | }, 21 | "dependencies": { 22 | "chance": { 23 | "version": "1.1.9", 24 | "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.9.tgz", 25 | "integrity": "sha512-TfxnA/DcZXRTA4OekA2zL9GH8qscbbl6X0ZqU4tXhGveVY/mXWvEQLt5GwZcYXTEyEFflVtj+pG8nc8EwSm1RQ==" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sort", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "chance": "^1.1.9" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/benchmark.js: -------------------------------------------------------------------------------- 1 | import { bogoSort } from './bogo.js'; 2 | import { bubbleSort } from './bubble.js'; 3 | import { quickSort } from './quick.js'; 4 | import { selectionSort } from './selection.js'; 5 | import { insertionSort } from './insertion.js'; 6 | import { mergeSort } from './merge.js'; 7 | import { heapSort } from './heap.js'; 8 | import { radixSort } from './radix.js'; 9 | import { cocktailShakerSort } from './cocktail.js'; 10 | import { shellSort } from './shell.js'; 11 | import { gnomeSort } from './gnome.js'; 12 | import { jsSort } from './jssort.js'; 13 | 14 | import Chance from 'chance'; 15 | 16 | const chance = new Chance(); 17 | 18 | // Helper Functions 19 | 20 | function makeShuffledRange(len) { 21 | const arr = []; 22 | for (let i = 0; i <= len; i++) { 23 | arr.push(i); 24 | } 25 | return arr.sort(() => Math.random() - 0.5); 26 | } 27 | 28 | function isSorted(arr) { 29 | let sorted = true; 30 | for (let i = 0; i < arr.length - 1; i++) { 31 | if (arr[i] > arr[i+1]) { 32 | sorted = false; 33 | break; 34 | } 35 | } 36 | return sorted; 37 | } 38 | 39 | function runIt(algo) { 40 | const cp = [...testData]; 41 | const start = performance.now(); 42 | const result = algo(cp); 43 | results.push({ name: algo.name, time: performance.now() - start }) 44 | !isSorted(result) && console.log(algo.name, 'sorting failed!'); 45 | result.length !== testData.length && console.log(algo.name, 'length mismatch!'); 46 | } 47 | 48 | // Main Testing 49 | 50 | // const testData = makeShuffledRange(10000); 51 | // const testData = makeRandomArrayOfChars(10000); 52 | // const testData = chance.n(chance.character, 10000); 53 | const testData = chance.n(chance.hammertime, 10000); 54 | const results = []; 55 | 56 | 57 | runIt(selectionSort); 58 | runIt(bubbleSort); 59 | runIt(quickSort); 60 | runIt(insertionSort); 61 | runIt(mergeSort); 62 | runIt(heapSort); 63 | runIt(cocktailShakerSort); 64 | runIt(shellSort); 65 | runIt(gnomeSort); 66 | runIt(radixSort); // only works on ints 67 | runIt(jsSort); 68 | // runIt(bogoSort); // careful now 69 | 70 | console.table(results.sort((a, b) => a.time - b.time)); 71 | -------------------------------------------------------------------------------- /src/bogo.js: -------------------------------------------------------------------------------- 1 | export function bogoSort(arr) { 2 | while (!sorted(arr)) { 3 | arr = shuffle(arr); 4 | } 5 | 6 | return arr; 7 | } 8 | 9 | function shuffle(arr) { 10 | let m = arr.length, 11 | t, 12 | i; 13 | 14 | while (m) { 15 | i = Math.floor(Math.random() * m--); 16 | 17 | t = arr[m]; 18 | arr[m] = arr[i]; 19 | arr[i] = t; 20 | } 21 | 22 | return arr; 23 | } 24 | 25 | function sorted(arr) { 26 | let sorted = true; 27 | 28 | for (let i = 0; i < arr.length - 1; i++) { 29 | if (arr[i + 1] < arr[i]) { 30 | sorted = false; 31 | } 32 | } 33 | 34 | return sorted; 35 | } 36 | -------------------------------------------------------------------------------- /src/bubble.js: -------------------------------------------------------------------------------- 1 | export function bubbleSort(arr) { 2 | for (let i = 0; i < arr.length; i++) { 3 | for (let j = 0; j < arr.length - i - 1; j++) { 4 | if (arr[j] > arr[j + 1]) { 5 | let temp = arr[j]; 6 | arr[j] = arr[j + 1]; 7 | arr[j + 1] = temp; 8 | } 9 | } 10 | } 11 | return arr; 12 | } 13 | -------------------------------------------------------------------------------- /src/cocktail.js: -------------------------------------------------------------------------------- 1 | // cocktail shaker sort 2 | export function cocktailShakerSort(arr) { 3 | let isSorted = true; 4 | while (isSorted) { 5 | for (let i = 0; i < arr.length - 1; i++) { 6 | if (arr[i] > arr[i + 1]) { 7 | let temp = arr[i]; 8 | arr[i] = arr[i + 1]; 9 | arr[i + 1] = temp; 10 | isSorted = true; 11 | } 12 | } 13 | 14 | if (!isSorted) break; 15 | 16 | isSorted = false; 17 | 18 | for (let j = arr.length - 1; j > 0; j--) { 19 | if (arr[j - 1] > arr[j]) { 20 | let temp = arr[j]; 21 | arr[j] = arr[j - 1]; 22 | arr[j - 1] = temp; 23 | isSorted = true; 24 | } 25 | } 26 | } 27 | 28 | return arr; 29 | } 30 | -------------------------------------------------------------------------------- /src/gnome.js: -------------------------------------------------------------------------------- 1 | export function gnomeSort(arr) { 2 | let i = 1; // start at 1 because we're comparing i-1 to i 3 | let j = 2; // start at 2 because we're comparing i-1 to i 4 | while (i < arr.length) { 5 | if (arr[i - 1] <= arr[i]) { 6 | i = j; 7 | j++; 8 | } else { 9 | [arr[i - 1], arr[i]] = [arr[i], arr[i - 1]]; // swap 10 | i--; 11 | if (i === 0) { 12 | i = j; 13 | j++; 14 | } 15 | } 16 | } 17 | return arr; 18 | } -------------------------------------------------------------------------------- /src/heap.js: -------------------------------------------------------------------------------- 1 | // heap sort 2 | export function heapSort(arr) { 3 | let len = arr.length; 4 | let end = len - 1; 5 | heapify(arr, len); 6 | while (end > 0) { 7 | swap(arr, end--, 0); 8 | siftDown(arr, 0, end); 9 | } 10 | return arr; 11 | } 12 | 13 | function heapify(arr, len) { 14 | let mid = Math.floor((len - 2) / 2); 15 | while (mid >= 0) { 16 | siftDown(arr, mid--, len - 1); 17 | } 18 | } 19 | 20 | function siftDown(arr, start, end) { 21 | let root = start, child, toSwap; 22 | while ((root * 2 + 1) <= end) { 23 | child = root * 2 + 1; 24 | toSwap = root; 25 | if (arr[toSwap] < arr[child]) { 26 | toSwap = child; 27 | } 28 | if (child + 1 <= end && arr[toSwap] < arr[child + 1]) { 29 | toSwap = child + 1; 30 | } 31 | if (toSwap === root) { 32 | return; 33 | } else { 34 | swap(arr, root, toSwap); 35 | root = toSwap; 36 | } 37 | } 38 | } 39 | 40 | function swap(arr, i, j) { 41 | [arr[i], arr[j]] = [arr[j], arr[i]]; 42 | } -------------------------------------------------------------------------------- /src/insertion.js: -------------------------------------------------------------------------------- 1 | export function insertionSort(arr) { 2 | for (let i = 1; i < arr.length; i++) { 3 | let current = arr[i]; 4 | 5 | let j = i - 1; 6 | 7 | while (j > -1 && current < arr[j]) { 8 | arr[j + 1] = arr[j]; 9 | j--; 10 | } 11 | arr[j + 1] = current; 12 | } 13 | return arr; 14 | } 15 | -------------------------------------------------------------------------------- /src/jssort.js: -------------------------------------------------------------------------------- 1 | export function jsSort(arr) { 2 | return arr.sort((a, b) => a - b); 3 | } -------------------------------------------------------------------------------- /src/merge.js: -------------------------------------------------------------------------------- 1 | export function mergeSort(arr) { 2 | const mid = arr.length / 2; 3 | 4 | if (arr.length < 2) { 5 | return arr; 6 | } 7 | 8 | const left = arr.splice(0, mid); 9 | return merge(mergeSort(left), mergeSort(arr)); 10 | } 11 | 12 | function merge(left, right) { 13 | let arr = []; 14 | while (left.length && right.length) { 15 | if (left[0] < right[0]) { 16 | arr.push(left.shift()); 17 | } else { 18 | arr.push(right.shift()); 19 | } 20 | } 21 | 22 | return [...arr, ...left, ...right]; 23 | } 24 | -------------------------------------------------------------------------------- /src/quick.js: -------------------------------------------------------------------------------- 1 | export function quickSort(arr, left = 0, right = arr.length - 1) { 2 | if (left >= right) { 3 | return; 4 | } 5 | 6 | let pivotIndex = partition(arr, left, right); 7 | quickSort(arr, left, pivotIndex - 1); 8 | quickSort(arr, pivotIndex + 1, right); 9 | 10 | return arr; 11 | } 12 | 13 | function partition(arr, left, right) { 14 | let pivotValue = arr[right]; 15 | let partitionIndex = left; 16 | 17 | for (let i = left; i < right; i++) { 18 | if (arr[i] < pivotValue) { 19 | swap(arr, i, partitionIndex); 20 | partitionIndex++; 21 | } 22 | } 23 | 24 | swap(arr, right, partitionIndex); 25 | return partitionIndex; 26 | } 27 | 28 | function swap(arr, firstIndex, secondIndex) { 29 | let temp = arr[firstIndex]; 30 | arr[firstIndex] = arr[secondIndex]; 31 | arr[secondIndex] = temp; 32 | } 33 | 34 | 35 | 36 | 37 | 38 | export function quickSortCheatMode(arr) { 39 | if (arr.length <= 1) return arr; 40 | let pivot = arr[0]; 41 | let left = arr.filter(x => x < pivot); 42 | let right = arr.filter(x => x > pivot); 43 | return [...quickSort(left), pivot, ...quickSort(right)] 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | // export function quickSort(arr) { 74 | 75 | // // if (arr.length < 2) { 76 | // // return arr; 77 | // // } 78 | // // const pivotIndex = Math.floor(arr.length / 2); 79 | // // const pivot = arr.splice(pivotIndex, 1)[0]; 80 | // // const left = []; 81 | // // const right = []; 82 | 83 | // // for (let i = 0; i < arr.length; i++) { 84 | // // if (arr[i] < pivot) { 85 | // // left.push(arr[i]); 86 | // // } else { 87 | // // right.push(arr[i]); 88 | // // } 89 | // // } 90 | 91 | // // return [...quickSort(left), pivot, ...quickSort(right)]; 92 | 93 | // } 94 | -------------------------------------------------------------------------------- /src/radix.js: -------------------------------------------------------------------------------- 1 | export function radixSort(arr) { 2 | let maxDigits = 0; 3 | 4 | for (let i = 0; i < arr.length; i++) { 5 | maxDigits = Math.max(maxDigits, getNumberOfDigits(arr[i])); 6 | } 7 | 8 | for (let i = 0; i < maxDigits; i++) { 9 | let buckets = Array.from({ length: 10 }, () => []); 10 | 11 | for (let j = 0; j < arr.length; j++) { 12 | let digit = getDigit(arr[j], i); 13 | buckets[digit].push(arr[j]); 14 | } 15 | 16 | arr = [].concat(...buckets); 17 | } 18 | 19 | return arr; 20 | } 21 | 22 | function getDigit(num, place) { 23 | return Math.floor(Math.abs(num) / Math.pow(10, place)) % 10; 24 | } 25 | 26 | function getNumberOfDigits(num) { 27 | return Math.floor(Math.log10(Math.abs(num))) + 1; 28 | } -------------------------------------------------------------------------------- /src/selection.js: -------------------------------------------------------------------------------- 1 | export function selectionSort(arr) { 2 | for (let i = 0; i < arr.length; i++) { 3 | let min = i; 4 | for (let j = i + 1; j < arr.length; j++) { 5 | if (arr[j] < arr[min]) { 6 | min = j; 7 | } 8 | } 9 | if (min !== i) { 10 | [arr[i], arr[min]] = [arr[min], arr[i]]; 11 | } 12 | } 13 | return arr; 14 | } 15 | -------------------------------------------------------------------------------- /src/shell.js: -------------------------------------------------------------------------------- 1 | // shell sort 2 | 3 | export function shellSort(arr) { 4 | const len = arr.length; 5 | let gap = Math.floor(len / 2); 6 | 7 | while (gap > 0) { 8 | for (let i = gap; i < len; i++) { 9 | let j = i; 10 | let current = arr[i]; 11 | while (j - gap >= 0 && current < arr[j - gap]) { 12 | arr[j] = arr[j - gap]; 13 | j = j - gap; 14 | } 15 | arr[j] = current; 16 | } 17 | gap = Math.floor(gap / 2); 18 | } 19 | return arr; 20 | } 21 | --------------------------------------------------------------------------------