├── .eslintrc.json ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── doc-config.json ├── gulpfile.js ├── package.json ├── readme.md ├── src ├── combinatorics │ ├── cartesianproduct.js │ ├── combinations.js │ ├── permutations.js │ └── variations-repetition.js ├── compression │ ├── LZW │ │ └── LZW.js │ ├── burrows-wheeler │ │ └── burrows-wheeler.js │ └── runlength │ │ └── runlength.js ├── data-structures │ ├── avl-tree.js │ ├── binary-search-tree.js │ ├── bloomfilter.js │ ├── edge.js │ ├── hash-table.js │ ├── heap.js │ ├── interval-tree.js │ ├── linked-list.js │ ├── red-black-tree.js │ ├── segment-tree.js │ ├── size-balanced-tree.js │ ├── splay-tree.js │ ├── suffix-tree.js │ └── vertex.js ├── graphics │ ├── bezier.js │ ├── bresenham-line-drawing.js │ └── graham.js ├── graphs │ ├── others │ │ ├── tarjan-connected-components.js │ │ └── topological-sort.js │ ├── searching │ │ ├── bfs.js │ │ └── dfs.js │ ├── shortest-path │ │ ├── bellman-ford.js │ │ ├── dijkstra.js │ │ └── floyd-warshall.js │ └── spanning-trees │ │ ├── kruskal.js │ │ └── prim.js ├── others │ ├── fibonacci.js │ ├── fibonacciMemory.js │ ├── hanoi.js │ ├── levenshtein-distance.js │ ├── min-coins-change.js │ ├── minimax.js │ └── minkowski-distance.js ├── primes │ ├── is-prime.js │ ├── prime-factor-tree.js │ ├── sieve-of-atkins.js │ └── sieve-of-eratosthenes.js ├── searching │ ├── binarysearch.js │ ├── interpolation-search.js │ ├── jump-search.js │ ├── knuth-morris-pratt.js │ ├── linearSearch.js │ ├── longest-common-subsequence.js │ ├── longest-increasing-subsequence.js │ ├── maximum-subarray-divide-and-conquer.js │ ├── maximum-subarray.js │ ├── quickselect.js │ └── recursive-binarysearch.js ├── sets │ ├── quickfind.js │ ├── quickunion.js │ └── weightquickunion.js ├── shuffle │ ├── fisheryates.js │ └── richarddurstenfeld.js └── sorting │ ├── 3-way-string-quicksort.js │ ├── bubblesort.js │ ├── bucketsort.js │ ├── countingsort.js │ ├── heapsort.js │ ├── insertion-binary-sort.js │ ├── insertionsort.js │ ├── lsd.js │ ├── mergesort.js │ ├── msd.js │ ├── oddeven-sort.js │ ├── quicksort-declarative.js │ ├── quicksort-middle.js │ ├── quicksort.js │ ├── radixsort.js │ ├── readme.md │ ├── recursive-insertionsort.js │ ├── selectionsort.js │ └── shellsort.js ├── test ├── compression │ └── burrows-wheeler │ │ └── burrows-wheeler.spec.js ├── data-structures │ ├── avl-tree.spec.js │ ├── binary-search-tree.spec.js │ ├── bloomfilter.spec.js │ ├── hash-table.spec.js │ ├── heap.spec.js │ ├── interval-tree.spec.js │ ├── linked-list.spec.js │ ├── red-black-tree.spec.js │ ├── segment-tree.spec.js │ ├── size-balanced-tree.spec.js │ └── splay-tree.spec.js ├── graphics │ ├── bezier.spec.js │ └── grapham.spec.js ├── graphs │ ├── others │ │ ├── tarjan-connected-components.spec.js │ │ └── topological-sort.spec.js │ ├── searching │ │ ├── bfs.spec.js │ │ └── dfs.spec.js │ ├── shortest-path │ │ ├── bellman-ford.spec.js │ │ └── dijkstra.spec.js │ └── spanning-trees │ │ └── kruskal.spec.js ├── others │ ├── fibonacci.spec.js │ ├── fibonacciMemory.spec.js │ ├── levenshtein-distance.spec.js │ ├── min-coins-sum.spec.js │ ├── minimax.spec.js │ └── minkowski-distance.spec.js ├── primes │ ├── is-prime.spec.js │ ├── prime-factor-tree.spec.js │ ├── sieve-of-atkins.spec.js │ └── sieve-of-eratosthenes.spec.js ├── searching │ ├── binarysearch.spec.js │ ├── interpolation-search.spec.js │ ├── jump-search.spec.js │ ├── knuth-morris-pratt.spec.js │ ├── linearSearch.spec.js │ ├── longest-common-subsequence.spec.js │ ├── longest-increasing-subsequence.spec.js │ ├── maximum-subarray-divide-and-conquer.spec.js │ ├── maximum-subarray.spec.js │ ├── quickselect.spec.js │ └── recursive-binarysearch.spec.js └── sorting │ ├── 3-way-string-quicksort.spec.js │ ├── bubblesort.spec.js │ ├── bucketsort.spec.js │ ├── countingsort.spec.js │ ├── heapsort.spec.js │ ├── insertionbinarysort.spec.js │ ├── insertionsort.spec.js │ ├── lsd.spec.js │ ├── mergesort.spec.js │ ├── msd.spec.js │ ├── oddeven-sort.spec.js │ ├── quicksort-declarative.spec.js │ ├── quicksort-middle.spec.js │ ├── quicksort.spec.js │ ├── radixsort.spec.js │ ├── recursiveinsertionsort.spec.js │ ├── selectionsort.spec.js │ ├── shellsort.spec.js │ └── sort.testcase.js └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "jquery": true, 5 | "node": true, 6 | "es6": true 7 | }, 8 | "globals": { 9 | "expect": true, 10 | "it": true, 11 | "describe": true, 12 | "beforeEach": true, 13 | "afterEach": true 14 | }, 15 | "parserOptions": { 16 | "ecmaVersion": 6 17 | }, 18 | "rules": { 19 | "camelcase": 2, 20 | "eqeqeq": 2, 21 | "indent": [ 22 | 2, 23 | 2, 24 | { 25 | "SwitchCase": 1 26 | } 27 | ], 28 | "no-use-before-define": [ 29 | 2, 30 | { 31 | "functions": false 32 | } 33 | ], 34 | "no-caller": 2, 35 | "new-cap": 0, 36 | "quotes": [ 37 | 2, 38 | "single" 39 | ], 40 | "no-unused-vars": 2, 41 | "strict": [ 42 | 2, 43 | "function" 44 | ], 45 | "no-extend-native": 2, 46 | "wrap-iife": [ 47 | 2, 48 | "any" 49 | ], 50 | "no-empty": 2, 51 | "no-plusplus": 2, 52 | "no-undef": 2, 53 | "linebreak-style": 0, 54 | "max-depth": [ 55 | 2, 56 | 4 57 | ], 58 | "no-loop-func": 2, 59 | "complexity": [ 60 | 2, 61 | 13 62 | ], 63 | "max-len": [ 64 | 2, 65 | { 66 | "code": 120, 67 | "ignoreComments": true 68 | } 69 | ], 70 | "max-params": [ 71 | 2, 72 | 5 73 | ], 74 | "curly": [ 75 | 2, 76 | "all" 77 | ], 78 | "keyword-spacing": [ 79 | 2, 80 | {} 81 | ], 82 | "one-var": [ 83 | 2, 84 | "never" 85 | ], 86 | "array-bracket-spacing": [ 87 | 2, 88 | "never", 89 | {} 90 | ], 91 | "space-in-parens": [ 92 | 2, 93 | "never" 94 | ], 95 | "key-spacing": [ 96 | 2, 97 | { 98 | "beforeColon": false, 99 | "afterColon": true 100 | } 101 | ], 102 | "quote-props": [ 103 | 2, 104 | "as-needed" 105 | ], 106 | "space-infix-ops": 2, 107 | "space-unary-ops": [ 108 | 2, 109 | { 110 | "words": false, 111 | "nonwords": false 112 | } 113 | ], 114 | "no-implicit-coercion": [ 115 | 2, 116 | { 117 | "boolean": false, 118 | "string": true, 119 | "number": true 120 | } 121 | ], 122 | "no-with": 2, 123 | "no-multiple-empty-lines": 2, 124 | "brace-style": [ 125 | 2, 126 | "1tbs", 127 | { 128 | "allowSingleLine": true 129 | } 130 | ], 131 | "eol-last": 2, 132 | "no-trailing-spaces": 2 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Use Node.js 13 | uses: actions/setup-node@v3 14 | with: 15 | node-version: '17.7.x' 16 | - run: yarn --frozen-lockfile 17 | - run: npm test 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | npm-debug.log 4 | debug 5 | dist 6 | .idea 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | script: npm run build 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at minko@gechev.io. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Minko Gechev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doc-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true 4 | }, 5 | "source": { 6 | "include": [ 7 | "./src/combinatorics/", 8 | "./src/compression/", 9 | "./src/data-structures/", 10 | "./src/graphics/", 11 | "./src/graphs/others/", 12 | "./src/graphs/searching/", 13 | "./src/graphs/shortest-path/", 14 | "./src/graphs/spanning-trees/", 15 | "./src/others/", 16 | "./src/primes/", 17 | "./src/searching/", 18 | "./src/sets/", 19 | "./src/shuffle/", 20 | "./src/sorting/" 21 | ], 22 | "includePattern": ".+\\.js(doc)?$", 23 | "excludePattern": "docs" 24 | }, 25 | "plugins": [], 26 | "opts": { 27 | "template": "node_modules/@jeremyckahn/minami", 28 | "encoding": "utf8", 29 | "destination": "dist", 30 | "recurse": true, 31 | "private": false, 32 | "readme": "./readme.md" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const eslint = require('gulp-eslint'); 3 | const jasmine = require('gulp-jasmine'); 4 | 5 | gulp.task('test', () => { 6 | 'use strict'; 7 | return gulp.src('test/**/*.spec.js') 8 | .pipe(jasmine()); 9 | }); 10 | 11 | gulp.task('lint', ()=> { 12 | 'use strict'; 13 | return gulp.src(['src/**/*.js', 'test/**/*.js']) 14 | .pipe(eslint()) 15 | .pipe(eslint.format()) 16 | .pipe(eslint.failAfterError()); 17 | }); 18 | 19 | gulp.task('build', gulp.parallel(['lint', 'test'])); 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-algorithms", 3 | "version": "0.0.0", 4 | "description": "Implementations of different computer science algorithms", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "devDependencies": { 10 | "@jeremyckahn/minami": "^1.3.1", 11 | "gh-pages": "^1.1.0", 12 | "gulp": "^4.0.2", 13 | "gulp-eslint": "^3.0.1", 14 | "gulp-jasmine": "^2.0.1", 15 | "jsdoc": "3.5.5", 16 | "live-server": "^1.2.0" 17 | }, 18 | "scripts": { 19 | "build": "gulp build", 20 | "test": "gulp test", 21 | "deploy": "npm run doc:build && gh-pages -d dist -b gh-pages", 22 | "doc": "npm run doc:build && npm run doc:view", 23 | "doc:build": "jsdoc -c doc-config.json", 24 | "doc:view": "live-server dist --port=9124" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git://github.com/mgechev/javascript-algorithms" 29 | }, 30 | "author": "@mgechev", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/mgechev/javascript-algorithms/issues" 34 | }, 35 | "homepage": "https://github.com/mgechev/javascript-algorithms" 36 | } 37 | -------------------------------------------------------------------------------- /src/combinatorics/cartesianproduct.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var cartesianProduct = (function () { 5 | var result; 6 | 7 | function cartesianProduct(sets, index, current) { 8 | if (index === sets.length) { 9 | return result.push(current.slice()); 10 | } 11 | for (var i = 0; i < sets[index].length; i += 1) { 12 | current[index] = sets[index][i]; 13 | cartesianProduct(sets, index + 1, current); 14 | } 15 | } 16 | 17 | /** 18 | * Calculates Cartesian product of provided sets. 19 | * 20 | * @module combinatorics/cartesianproduct 21 | * @public 22 | * @param {Array} sets Array of sets. 23 | * @return {Array} Cartesian product of provided sets. 24 | * 25 | * @example 26 | * var product = require('path-to-algorithms/src/combinatorics/' + 27 | * 'cartesianproduct').cartesianProduct; 28 | * var result = product([[1, 2, 3], [3, 2, 1]]); 29 | * // [ [ 1, 3 ], 30 | * // [ 1, 2 ], 31 | * // [ 1, 1 ], 32 | * // [ 2, 3 ], 33 | * // [ 2, 2 ], 34 | * // [ 2, 1 ], 35 | * // [ 3, 3 ], 36 | * // [ 3, 2 ], 37 | * // [ 3, 1 ] ] 38 | * console.log(result); 39 | */ 40 | return function (sets) { 41 | result = []; 42 | cartesianProduct(sets, 0, []); 43 | return result; 44 | }; 45 | }()); 46 | 47 | exports.cartesianProduct = cartesianProduct; 48 | 49 | }((typeof window === 'undefined') ? module.exports : window)); 50 | -------------------------------------------------------------------------------- /src/combinatorics/combinations.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var combinations = (function () { 5 | var res = []; 6 | 7 | function combinations(arr, k, start, idx, current) { 8 | if (idx === k) { 9 | res.push(current.slice()); 10 | return; 11 | } 12 | for (var i = start; i < arr.length; i += 1) { 13 | current[idx] = arr[i]; 14 | combinations(arr, k, i + 1, idx + 1, current); 15 | } 16 | } 17 | 18 | /** 19 | * Finds all the combinations of given array.

20 | * A combination is a way of selecting members from a grouping, 21 | * such that (unlike permutations) the order of selection does not matter. 22 | * For example given three fruits, say an apple, an orange and a pear, 23 | * there are three combinations of two that can be drawn from this set: 24 | * an apple and a pear; an apple and an orange; or a pear and an orange. 25 | * 26 | * @example 27 | * 28 | * var combinations = require('path-to-algorithms/src/' + 29 | * 'combinatorics/combinations').combinations; 30 | * var result = combinations(['apple', 'orange', 'pear'], 2); 31 | * // [['apple', 'orange'], 32 | * // ['apple', 'pear'], 33 | * // ['orange', 'pear']] 34 | * console.log(result); 35 | * 36 | * @module combinatorics/combinations 37 | * @public 38 | * @param arr {Array} Set of items. 39 | * @param k {Number} Size of each combination. 40 | * @return {Array} Returns all combinations. 41 | */ 42 | return function (arr, k) { 43 | res = []; 44 | combinations(arr, k, 0, 0, []); 45 | var temp = res; 46 | // Free the extra memory 47 | res = null; 48 | return temp; 49 | }; 50 | }()); 51 | 52 | exports.combinations = combinations; 53 | 54 | }((typeof window === 'undefined') ? module.exports : window)); 55 | -------------------------------------------------------------------------------- /src/combinatorics/permutations.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | var permutations = (function () { 4 | 5 | var res; 6 | 7 | function swap(arr, i, j) { 8 | var temp = arr[i]; 9 | arr[i] = arr[j]; 10 | arr[j] = temp; 11 | } 12 | 13 | function permutations(arr, current) { 14 | if (current >= arr.length) { 15 | return res.push(arr.slice()); 16 | } 17 | for (var i = current; i < arr.length; i += 1) { 18 | swap(arr, i, current); 19 | permutations(arr, current + 1); 20 | swap(arr, i, current); 21 | } 22 | } 23 | 24 | /** 25 | * Finds all the permutations of given array.

26 | * Permutation relates to the act of rearranging, or permuting, 27 | * all the members of a set into some sequence or order. 28 | * For example there are six permutations of the set {1,2,3}, namely: 29 | * (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), and (3,2,1).

30 | * Complexity: O(N*N!). 31 | * 32 | * @example 33 | * 34 | * var permutations = require('path-to-algorithms/src/' + 35 | * 'combinatorics/permutations').permutations; 36 | * var result = permutations(['apple', 'orange', 'pear']); 37 | * 38 | * // [ [ 'apple', 'orange', 'pear' ], 39 | * // [ 'apple', 'pear', 'orange' ], 40 | * // [ 'orange', 'apple', 'pear' ], 41 | * // [ 'orange', 'pear', 'apple' ], 42 | * // [ 'pear', 'orange', 'apple' ], 43 | * // [ 'pear', 'apple', 'orange' ] ] 44 | * console.log(result); 45 | * 46 | * @module combinatorics/permutations 47 | * @public 48 | * @param {Array} arr Array to find the permutations of. 49 | * @returns {Array} Array containing all the permutations. 50 | */ 51 | return function (arr) { 52 | res = []; 53 | permutations(arr, 0); 54 | var temp = res; 55 | // Free the extra memory 56 | res = null; 57 | return temp; 58 | }; 59 | }()); 60 | 61 | exports.permutations = permutations; 62 | 63 | }((typeof window === 'undefined') ? module.exports : window)); 64 | -------------------------------------------------------------------------------- /src/combinatorics/variations-repetition.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var variationsWithRepetition = (function () { 5 | var res; 6 | 7 | function variations(arr, k, index, current) { 8 | if (k === index) { 9 | return res.push(current.slice()); 10 | } 11 | for (var i = 0; i < arr.length; i += 1) { 12 | current[index] = arr[i]; 13 | variations(arr, k, index + 1, current); 14 | } 15 | } 16 | 17 | /** 18 | * Finds all the variations with repetition of given array.

19 | * Variations with repetition is the number of ways to sample k elements 20 | * from a set of elements (which may be repeated). 21 | * 22 | * @example 23 | * var variations = require('path-to-algorithms/src/combinatorics/' + 24 | * 'variations-repetition').variationsWithRepetition; 25 | * var result = variations(['apple', 'orange', 'pear'], 2); 26 | * 27 | * // [['apple', 'apple'], 28 | * // ['apple', 'orange'], 29 | * // ['apple', 'pear'], 30 | * // ['orange', 'apple'], 31 | * // ['orange', 'orange'], 32 | * // ['orange', 'pear'], 33 | * // ['pear', 'apple'], 34 | * // ['pear', 'orange'], 35 | * // ['pear', 'pear']] 36 | * console.log(result); 37 | * 38 | * @module combinatorics/variations-repetition 39 | * @public 40 | * @param arr {Array} Set of items. 41 | * @param k {Number} Size of each combination. 42 | * @return {Array} Returns all combinations. 43 | */ 44 | return function (arr, k) { 45 | res = []; 46 | variations(arr, k, 0, []); 47 | var temp = res; 48 | res = undefined; 49 | return temp; 50 | }; 51 | }()); 52 | 53 | exports.variationsWithRepetition = variationsWithRepetition; 54 | 55 | }((typeof window === 'undefined') ? module.exports : window)); 56 | -------------------------------------------------------------------------------- /src/compression/LZW/LZW.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LZW Encoding/Decoding 3 | * 4 | * Lempel–Ziv–Welch (LZW) is a universal lossless data 5 | * compression algorithm. It is an improved implementation 6 | * of the LZ78 algorithm. 7 | * 8 | * @example 9 | * var lzwModule = require('path-to-algorithms/src/compression'+ 10 | * '/LZW/LZW'); 11 | * var lzw = new lzwModule.LZW(); 12 | * 13 | * var compressed = lzw.compress("ABCABCABCABCABCABC"); 14 | * console.log(compressed); 15 | * 16 | * var decompressed = lzw.decompress(compressed); 17 | * console.log(decompressed); 18 | * 19 | * @module compression/LZW/LZW 20 | */ 21 | (function (exports) { 22 | 'use strict'; 23 | 24 | exports.LZW = function () { 25 | this.dictionarySize = 256; 26 | }; 27 | 28 | exports.LZW.compress = function (data) { 29 | var i; 30 | var dictionary = {}; 31 | var character; 32 | var wc; 33 | var w = ''; 34 | var result = []; 35 | 36 | for (i = 0; i < this.dictionarySize; i = i + 1) { 37 | dictionary[String.fromCharCode(i)] = i; 38 | } 39 | 40 | for (i = 0; i < data.length; i = i + 1) { 41 | character = data.charAt(i); 42 | wc = w + character; 43 | if (dictionary.hasOwnProperty(wc)) { 44 | w = wc; 45 | } else { 46 | result.push(dictionary[w]); 47 | dictionary[wc] = this.dictionarySize; 48 | this.dictionarySize = this.dictionarySize + 1; 49 | w = String(character); 50 | } 51 | } 52 | 53 | if (w !== '') { 54 | result.push(dictionary[w]); 55 | } 56 | 57 | return result; 58 | }; 59 | 60 | exports.LZW.decompress = function (compressedData) { 61 | var i; 62 | var dictionary = []; 63 | var w; 64 | var result; 65 | var key; 66 | var entry = ''; 67 | 68 | for (i = 0; i < this.dictionarySize; i = i + 1) { 69 | dictionary[i] = String.fromCharCode(i); 70 | } 71 | 72 | w = String.fromCharCode(compressedData[0]); 73 | result = w; 74 | 75 | for (i = 1; i < compressedData.length; i = i + 1) { 76 | key = compressedData[i]; 77 | if (dictionary[key]) { 78 | entry = dictionary[key]; 79 | } else { 80 | if (key === this.dictionarySize) { 81 | entry = w + w.charAt(0); 82 | } else { 83 | return null; 84 | } 85 | } 86 | 87 | result += entry; 88 | dictionary[this.dictionarySize] = w + entry.charAt(0); 89 | this.dictionarySize = this.dictionarySize + 1; 90 | w = entry; 91 | } 92 | 93 | return result; 94 | }; 95 | })(typeof window === 'undefined' ? module.exports : window); 96 | -------------------------------------------------------------------------------- /src/compression/burrows-wheeler/burrows-wheeler.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Burrows Wheeler. 6 | * 7 | * This algorithm is commonly used as a step in the process of compressing data, 8 | * it rearranges a character string into runs of similar characters making algorithms 9 | * like move-to-front transform and run-length encoding reach higher compression 10 | * rates. This implementation only supports characters with ascii code greater than $(36) as 11 | * 36 is used at the process of encode and decode. 12 | * 13 | * @example 14 | * const burrows = require('path-to-algorithms/src/burrows-wheeler/burrows-wheeler').burrowsWheeler; 15 | * const s = 'ananabanana'; 16 | * const encodedStr = burrows.encode(s); 17 | * console.log(encodedStr); 18 | * const decodedStr = burrows.decode(encodedStr); 19 | * console.log(decodedStr); 20 | * 21 | * @module compression/burrows-wheeler/burrows-wheeler 22 | */ 23 | exports.burrowsWheeler = function() { 24 | 25 | } 26 | 27 | /** 28 | * Consumes n^2 space. 29 | */ 30 | exports.burrowsWheeler.encode = function(str) { 31 | str = '$' + str; 32 | var combinations = []; 33 | for (let i = 0; i < str.length; i += 1) { 34 | combinations.push(str.substring(i) + str.substring(0, i)); 35 | } 36 | var sorted = combinations.sort(); 37 | var result = []; 38 | for (let i = 0; i < sorted.length; i += 1) { 39 | result.push(combinations[i][str.length - 1]); 40 | } 41 | return result.join(''); 42 | } 43 | 44 | exports.burrowsWheeler.decode = function(encodedStr) { 45 | const sortedCharSequence = encodedStr.split('').sort().join(''); 46 | const leftSide = {}; 47 | const rightSide = {}; 48 | var maxEachCharLeft = {}; 49 | var maxEachCharRight = {}; 50 | 51 | for (let i = 0; i < encodedStr.length; i += 1) { 52 | var idLeft = sortedCharSequence[i]; 53 | if (idLeft in maxEachCharLeft) { 54 | maxEachCharLeft[idLeft] = maxEachCharLeft[idLeft] + 1; 55 | } else { 56 | maxEachCharLeft[idLeft] = 1; 57 | } 58 | idLeft += String(maxEachCharLeft[idLeft]); 59 | 60 | var idRight = encodedStr[i]; 61 | if (idRight in maxEachCharRight) { 62 | maxEachCharRight[idRight] = maxEachCharRight[idRight] + 1; 63 | } else { 64 | maxEachCharRight[idRight] = 1; 65 | } 66 | idRight += String(maxEachCharRight[idRight]); 67 | 68 | leftSide[idLeft] = {char: sortedCharSequence[i], right: idRight}; 69 | rightSide[idRight] = {char: encodedStr[i], left: idRight}; 70 | } 71 | var result = ''; 72 | var firstChar = sortedCharSequence[0]; 73 | var searchChar = firstChar + '1'; 74 | var endChar = searchChar; 75 | while (rightSide[leftSide[searchChar].right].left !== endChar) { 76 | result += leftSide[searchChar].char; 77 | searchChar = rightSide[leftSide[searchChar].right].left; 78 | } 79 | result += leftSide[searchChar].char; 80 | result = result.substring(1).split('').reverse().join(''); 81 | return result; 82 | } 83 | 84 | }(typeof exports === 'undefined' ? window : exports)); 85 | -------------------------------------------------------------------------------- /src/compression/runlength/runlength.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Run-length encoding. 3 | * The idea of this algorithm is to remove the usless zeros and 4 | * give us representation of string in binary which in which the 5 | * zeros will be stripped and replaced with their count. 6 | */ 7 | (function (exports) { 8 | 'use strict'; 9 | 10 | var runLengthEncoding = (function () { 11 | 12 | /** 13 | * Converts a given string to sequence of numbers 14 | * This takes O(n). 15 | */ 16 | function convertToAscii(str) { 17 | var result = []; 18 | var currentChar = ''; 19 | var i = 0; 20 | for (; i < str.length; i += 1) { 21 | currentChar = str[i].charCodeAt(0).toString(2); 22 | currentChar = new Array(9 - currentChar.length).join('0') + currentChar; 23 | result.push(currentChar); 24 | } 25 | return result.join(''); 26 | } 27 | 28 | /** 29 | * Encodes the binary string to run-length encoding. 30 | * Takes O(n^2). 31 | */ 32 | function runLength(vector) { 33 | var result = []; 34 | var zeros = 0; 35 | var zerosTemp = ''; 36 | var i = 0; 37 | for (; i < vector.length; i += 1) { 38 | if (vector[i] === '0') { 39 | zeros += 1; 40 | } else { 41 | zerosTemp = zeros.toString(2); 42 | result.push(new Array(zerosTemp.length).join('1')); 43 | result.push('0' + zerosTemp); 44 | zeros = 0; 45 | } 46 | } 47 | return result.join(''); 48 | } 49 | 50 | /** 51 | * Accepts a string and returns it's run-length 52 | * encoded binary representation. 53 | * Takes O(n^2). 54 | */ 55 | return function (str) { 56 | var asciiString = convertToAscii(str); 57 | return runLength(asciiString); 58 | }; 59 | 60 | }()); 61 | 62 | exports.runLength = runLengthEncoding; 63 | 64 | }(typeof exports === 'undefined' ? window : exports)); 65 | -------------------------------------------------------------------------------- /src/data-structures/edge.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Graph edge. 6 | * 7 | * @constructor 8 | * @public 9 | * @param {Vertex} e Vertex which this edge connects. 10 | * @param {Vertex} v Vertex which this edge connects. 11 | * @param {Number} distance Weight of the edge. 12 | * @module data-structures/edge 13 | */ 14 | exports.Edge = function (e, v, distance) { 15 | this.from = e; 16 | this.to = v; 17 | this.distance = distance; 18 | }; 19 | 20 | })(typeof window === 'undefined' ? module.exports : window); 21 | -------------------------------------------------------------------------------- /src/data-structures/segment-tree.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implementation of a segment tree. 3 | * 4 | * @example 5 | * var SegmentTree = require('path-to-algorithms/src/data-structures'+ 6 | * '/segment-tree').SegmentTree; 7 | * 8 | * var tree = SegmentTree.indexArray([-1, 2, 4, 0], Infinity, function (a, b) { 9 | * return Math.min(a, b); 10 | * }); 11 | * 12 | * @public 13 | * @constructor 14 | * @param {any} placeholder A placeholder value dpendent on the aggregate. 15 | * @param {Function} aggregate Generates the values for the intermediate nodes. 16 | * @module data-structures/segment-tree 17 | */ 18 | (function (exports) { 19 | 20 | 'use strict'; 21 | 22 | /** 23 | * SegmentTree constructor. 24 | * 25 | * @public 26 | * @constructor 27 | * @param {any} invalidValue Invalid value to be returned depending 28 | * on the aggregate. 29 | * @param {Function} aggregate Function to generate the intermediate 30 | * values in the tree. 31 | */ 32 | function SegmentTree(invalidValue, aggregate) { 33 | this._data = []; 34 | this._original = null; 35 | this._invalidValue = invalidValue; 36 | this._aggregate = aggregate; 37 | } 38 | 39 | /** 40 | * Creates a segment tree using an array passed as element. 41 | * 42 | * @static 43 | * @public 44 | * @param {Array} array Array to be indexed. 45 | * @param {Function} aggregate Function used for generation of 46 | * intermediate nodes. 47 | */ 48 | SegmentTree.indexArray = function (array, placeholder, aggregate) { 49 | var segmentize = function (original, data, lo, hi, idx) { 50 | if (lo === hi) { 51 | data[idx] = original[lo]; 52 | } else { 53 | var mid = Math.floor((lo + hi) / 2); 54 | var left = 2 * idx + 1; 55 | var right = 2 * idx + 2; 56 | segmentize(original, data, lo, mid, left); 57 | segmentize(original, data, mid + 1, hi, right); 58 | data[idx] = aggregate(data[left], data[right]); 59 | } 60 | }; 61 | var result = []; 62 | if (array && array.length) { 63 | segmentize(array, result, 0, array.length - 1, 0); 64 | } 65 | var tree = new SegmentTree(placeholder, aggregate); 66 | tree._data = result; 67 | tree._original = array; 68 | return tree; 69 | }; 70 | 71 | /** 72 | * Queries the SegmentTree in given range based on the set aggregate. 73 | * 74 | * @param {Number} start The start index of the interval. 75 | * @param {Number} end The end index of the interval. 76 | */ 77 | SegmentTree.prototype.query = function (start, end) { 78 | if (start > end) { 79 | throw new Error('The start index should be smaller by the end index'); 80 | } 81 | var findEl = function (originalArrayStart, originalArrayEnd, current) { 82 | if (start > originalArrayEnd) { 83 | return this._invalidValue; 84 | } 85 | if (end < originalArrayStart) { 86 | return this._invalidValue; 87 | } 88 | if (start === originalArrayStart && end === originalArrayEnd || 89 | originalArrayStart === originalArrayEnd) { 90 | return this._data[current]; 91 | } 92 | var originalArrayMid = 93 | Math.floor((originalArrayStart + originalArrayEnd) / 2); 94 | return this._aggregate( 95 | findEl(originalArrayStart, originalArrayMid, 2 * current + 1), 96 | findEl(originalArrayMid + 1, originalArrayEnd, 2 * current + 2) 97 | ); 98 | }.bind(this); 99 | return findEl(0, this._original.length - 1, 0, this._aggregate); 100 | }; 101 | 102 | exports.SegmentTree = SegmentTree; 103 | 104 | }(typeof window === 'undefined' ? module.exports : window)); 105 | 106 | -------------------------------------------------------------------------------- /src/data-structures/suffix-tree.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function Node(val) { 5 | this.value = val; 6 | this.nodes = {}; 7 | } 8 | 9 | function SuffixTree() { 10 | this.root = new Node(); 11 | } 12 | 13 | SuffixTree.prototype.addNode = (function () { 14 | 15 | function maxPrefix(a, b) { 16 | var res = []; 17 | for (var i = 0; i < Math.min(a.length, b.length); i += 1) { 18 | if (a[i] === b[i]) { 19 | res.push(a[i]); 20 | } else { 21 | return ''; 22 | } 23 | } 24 | return res.join(''); 25 | } 26 | 27 | function addNode(suffix, current) { 28 | // Empty string already exists in the suffix tree 29 | if (!suffix) { 30 | return; 31 | } 32 | // The suffix is already inside the tree 33 | if (current.value === suffix) { 34 | return; 35 | } 36 | // Insert recursively 37 | if (current.nodes[suffix[0]]) { 38 | return addNode(suffix.substr(1, suffix.length), 39 | current.nodes[suffix[0]]); 40 | } 41 | // Find the maximum prefix and split the current node if prefix exists 42 | var prefix = maxPrefix(current.value, suffix); 43 | if (prefix.length) { 44 | var temp = current.value; 45 | var suffixSuffix = suffix.substr(prefix.length, suffix.length); 46 | var currentSuffix = temp.substr(prefix.length, temp.length); 47 | current.value = prefix; 48 | addNode(currentSuffix, current); 49 | addNode(suffixSuffix, current); 50 | // If prefix doesn't exists add new child node 51 | } else { 52 | current.nodes[suffix[0]] = new Node(suffix); 53 | } 54 | } 55 | 56 | return function (suffix) { 57 | addNode(suffix, this.root); 58 | }; 59 | }()); 60 | 61 | // O(n^2) or even O(n^3) because of maxPrefix 62 | SuffixTree.prototype.build = function (string) { 63 | this.root.value = string; 64 | for (var i = 1; i < string.length; i += 1) { 65 | this.addNode(string.substr(i, string.length)); 66 | } 67 | }; 68 | 69 | exports.Node = Node; 70 | exports.SuffixTree = SuffixTree; 71 | 72 | }(typeof exports === 'undefined' ? window : exports)); 73 | -------------------------------------------------------------------------------- /src/data-structures/vertex.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Graph vertex. 6 | * 7 | * @constructor 8 | * @public 9 | * @param {Number} id Id of the vertex. 10 | * @module data-structures/vertex 11 | */ 12 | exports.Vertex = function (id) { 13 | this.id = id; 14 | }; 15 | 16 | })(typeof window === 'undefined' ? module.exports : window); 17 | -------------------------------------------------------------------------------- /src/graphics/bezier.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function linearBezier(p0, p1, t) { 5 | return p0 + t * (p1 - p0); 6 | } 7 | 8 | function quadraticBezier(p0, p1, p2, t) { 9 | return linearBezier(linearBezier(p0, p1, t), linearBezier(p1, p2, t), t); 10 | } 11 | 12 | function cubicBezier(p0, p1, p2, p3, t) { 13 | return linearBezier(quadraticBezier(p0, p1, p2, t), quadraticBezier(p1, p2, p3, t), t); 14 | } 15 | 16 | exports.linearBezier = linearBezier; 17 | exports.quadraticBezier = quadraticBezier; 18 | exports.cubicBezier = cubicBezier; 19 | })(typeof exports === 'undefined' ? window : exports); 20 | -------------------------------------------------------------------------------- /src/graphics/bresenham-line-drawing.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Draws (prints) the given coordinates 6 | * @param {number} x The first coordinate of the point 7 | * @param {number} y The second coordinate of the point 8 | */ 9 | function drawPoint(x, y) { 10 | console.log(x, y); 11 | } 12 | 13 | /** 14 | * Bresenham's line drawing algorithm. 15 | * It has complexity O(n) 16 | * @param {number} x1 The first coordinate of the beginning of the line 17 | * @param {number} y1 The second coordinate of the beginning of the line 18 | * @param {number} x2 The first coordinate of the end of the line 19 | * @param {number} y2 The second coordinate of the end of the line 20 | * @param {function} draw Optional custom drawing function. 21 | */ 22 | function drawLine(x1, y1, x2, y2, draw) { 23 | var drawPointStrategy = draw || drawPoint; 24 | var dx = Math.abs(x2 - x1); 25 | var dy = Math.abs(y2 - y1); 26 | var cx = (x1 < x2) ? 1 : -1; 27 | var cy = (y1 < y2) ? 1 : -1; 28 | var error = dx - dy; 29 | var doubledError; 30 | 31 | while (x1 !== x2 || y1 !== y2) { 32 | drawPointStrategy(x1, y1); 33 | doubledError = error + error; 34 | if (doubledError > -dy) { 35 | error -= dy; 36 | x1 += cx; 37 | } 38 | if (doubledError < dx) { 39 | error += dx; 40 | y1 += cy; 41 | } 42 | } 43 | } 44 | 45 | exports.drawLine = drawLine; 46 | 47 | }(typeof exports === 'undefined' ? window : exports)); 48 | -------------------------------------------------------------------------------- /src/graphics/graham.js: -------------------------------------------------------------------------------- 1 | (function(exports) { 2 | 'use strict'; 3 | 4 | const slope = (p, a) => (a.y - p.y) / (a.x - p.x); 5 | 6 | const dist = (a, b) => Math.sqrt((b.y - a.y) * (b.y - a.y) + (b.x - a.x) * (b.x - a.x)); 7 | 8 | const sort = (p, memo, a, b) => { 9 | const sa = slope(p, a); 10 | const sb = slope(p, b); 11 | [[sa, a], [sb, b]].forEach(e => { 12 | const el = memo.get(e[0]); 13 | if (!el || dist(p, el) < dist(p, e[1])) { 14 | memo.set(e[0], e[1]); 15 | } 16 | }); 17 | return sa - sb; 18 | }; 19 | 20 | const ccw = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); 21 | 22 | /** 23 | * Graham's algorithm for calculating the convex hull. 24 | * 25 | * @public 26 | * @module graphics/graham 27 | * @param {Array} all 28 | * @returns {Array} 29 | * 30 | * @example 31 | * const points = [ 32 | * { x: 0, y: 0 }, 33 | * { x: 1, y: 0 }, 34 | * { x: 0, y: 1 }, 35 | * { x: 0.15, y: 0.15 }, 36 | * { x: 0.5, y: 0.5 } 37 | * ]; 38 | * const list = convexHull(points); 39 | * // [{ x: 0, y: 0 }, 40 | * // { x: 1, y: 0 }, 41 | * // { x: 0.5, y: 0.5 }, 42 | * // { x: 0, y: 1 }] 43 | */ 44 | const convexHull = all => { 45 | if (!all.length) { 46 | return []; 47 | } 48 | 49 | const p = all.reduce((a, c) => { 50 | if (a.y < c.y) { 51 | return a; 52 | } 53 | if (a.y > c.y) { 54 | return c; 55 | } 56 | if (a.x < c.x) { 57 | return a; 58 | } 59 | return c; 60 | }); 61 | 62 | const memo = new Map(); 63 | const stack = []; 64 | 65 | all 66 | .sort(sort.bind(null, p, memo)) 67 | .filter(c => memo.get(slope(p, c)) === c) 68 | .forEach(p => { 69 | while (stack.length > 1 && ccw(stack[stack.length - 2], stack[stack.length - 1], p) < 0) { 70 | stack.pop(); 71 | } 72 | stack.push(p); 73 | }); 74 | 75 | return stack; 76 | }; 77 | 78 | exports.convexHull = convexHull; 79 | })(typeof exports === 'undefined' ? window : exports); 80 | -------------------------------------------------------------------------------- /src/graphs/others/tarjan-connected-components.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Tarjan's algorithm for finding the connected components in a graph.

6 | * Time complexity: O(|E| + |V|) where E is a number of edges and |V| 7 | * is the number of nodes. 8 | * 9 | * @public 10 | * @module graphs/others/tarjan-connected-components 11 | * @param {Array} graph Adjacency list, which represents the graph. 12 | * @returns {Array} Connected components. 13 | * 14 | * @example 15 | * var tarjanConnectedComponents = 16 | * require('path-to-algorithms/src/graphs/' + 17 | * 'others/tarjan-connected-components').tarjanConnectedComponents; 18 | * var graph = { 19 | * v1: ['v2', 'v5'], 20 | * v2: [], 21 | * v3: ['v1', 'v2', 'v4', 'v5'], 22 | * v4: [], 23 | * v5: [] 24 | * }; 25 | * var vertices = topsort(graph); // ['v3', 'v4', 'v1', 'v5', 'v2'] 26 | */ 27 | function tarjanConnectedComponents(graph) { 28 | graph = graph || {}; 29 | const indexes = {}; 30 | const lowIndexes = {}; 31 | const onStack = {}; 32 | const result = []; 33 | const stack = []; 34 | var index = 1; 35 | 36 | const connectedComponent = function (node) { 37 | stack.push(node); 38 | onStack[node] = true; 39 | indexes[node] = index; 40 | lowIndexes[node] = index; 41 | index += 1; 42 | graph[node].forEach(function (n) { 43 | if (indexes[n] === undefined) { 44 | connectedComponent(n); 45 | lowIndexes[node] = Math.min(lowIndexes[n], lowIndexes[node]); 46 | } else if (onStack[n]) { 47 | lowIndexes[node] = Math.min(lowIndexes[node], indexes[n]); 48 | } 49 | }); 50 | // This is a "root" node 51 | const cc = []; 52 | if (indexes[node] === lowIndexes[node]) { 53 | var current; 54 | do { 55 | current = stack.pop(); 56 | onStack[current] = false; 57 | cc.push(current); 58 | } while (stack.length > 0 && node !== current); 59 | result.push(cc); 60 | } 61 | }; 62 | 63 | Object.keys(graph) 64 | .forEach(function (n) { 65 | if (!indexes[n]) { 66 | connectedComponent(n); 67 | } 68 | }); 69 | 70 | return result; 71 | } 72 | 73 | exports.tarjanConnectedComponents = tarjanConnectedComponents; 74 | 75 | }(typeof exports === 'undefined' ? window : exports)); 76 | -------------------------------------------------------------------------------- /src/graphs/others/topological-sort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var topologicalSort = (function () { 5 | 6 | function topologicalSortHelper(node, visited, temp, graph, result) { 7 | temp[node] = true; 8 | var neighbors = graph[node]; 9 | for (var i = 0; i < neighbors.length; i += 1) { 10 | var n = neighbors[i]; 11 | if (temp[n]) { 12 | throw new Error('The graph is not a DAG'); 13 | } 14 | if (!visited[n]) { 15 | topologicalSortHelper(n, visited, temp, graph, result); 16 | } 17 | } 18 | temp[node] = false; 19 | visited[node] = true; 20 | result.push(node); 21 | } 22 | 23 | /** 24 | * Topological sort algorithm of a directed acyclic graph.

25 | * Time complexity: O(|E| + |V|) where E is a number of edges 26 | * and |V| is the number of nodes. 27 | * 28 | * @public 29 | * @module graphs/others/topological-sort 30 | * @param {Array} graph Adjacency list, which represents the graph. 31 | * @returns {Array} Ordered vertices. 32 | * 33 | * @example 34 | * var topsort = 35 | * require('path-to-algorithms/src/graphs/' + 36 | * 'others/topological-sort').topologicalSort; 37 | * var graph = { 38 | * v1: ['v2', 'v5'], 39 | * v2: [], 40 | * v3: ['v1', 'v2', 'v4', 'v5'], 41 | * v4: [], 42 | * v5: [] 43 | * }; 44 | * var vertices = topsort(graph); // ['v3', 'v4', 'v1', 'v5', 'v2'] 45 | */ 46 | return function (graph) { 47 | var result = []; 48 | var visited = []; 49 | var temp = []; 50 | for (var node in graph) { 51 | if (!visited[node] && !temp[node]) { 52 | topologicalSortHelper(node, visited, temp, graph, result); 53 | } 54 | } 55 | return result.reverse(); 56 | }; 57 | }()); 58 | 59 | exports.topologicalSort = topologicalSort; 60 | 61 | }(typeof exports === 'undefined' ? window : exports)); 62 | -------------------------------------------------------------------------------- /src/graphs/searching/bfs.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var bfs = (function () { 5 | 6 | function buildPath(parents, targetNode) { 7 | var result = [targetNode]; 8 | while (parents[targetNode] !== null) { 9 | targetNode = parents[targetNode]; 10 | result.push(targetNode); 11 | } 12 | return result.reverse(); 13 | } 14 | 15 | /** 16 | * Breath-First graph searching algorithm. 17 | * Returns the shortest path between startNode and targetNode.

18 | * Time complexity: O(|V|^2). 19 | * 20 | * @public 21 | * @module graphs/searching/bfs 22 | * @param {Array} graph Adjacency matrix, which represents the graph. 23 | * @param {Number} startNode Start node. 24 | * @param {Number} targetNode Target, which should be reached. 25 | * @returns {Array} Shortest path from startNode to targetNode. 26 | * 27 | * @example 28 | * var bfs = require('path-to-algorithms/src/graphs/searching/bfs').bfs; 29 | * var graph = [[1, 1, 0, 0, 1, 0], 30 | * [1, 0, 1, 0, 1, 0], 31 | * [0, 1, 0, 1, 0, 0], 32 | * [0, 0, 1, 0, 1, 1], 33 | * [1, 1, 0, 1, 0, 0], 34 | * [0, 0, 0, 1, 0, 0]]; 35 | * var shortestPath = bfs(graph, 1, 5); // [1, 2, 3, 5] 36 | */ 37 | return function (graph, startNode, targetNode) { 38 | var parents = []; 39 | var queue = []; 40 | var visited = []; 41 | var current; 42 | queue.push(startNode); 43 | parents[startNode] = null; 44 | visited[startNode] = true; 45 | while (queue.length) { 46 | current = queue.shift(); 47 | if (current === targetNode) { 48 | return buildPath(parents, targetNode); 49 | } 50 | for (var i = 0; i < graph.length; i += 1) { 51 | if (i !== current && graph[current][i] && !visited[i]) { 52 | parents[i] = current; 53 | visited[i] = true; 54 | queue.push(i); 55 | } 56 | } 57 | } 58 | return null; 59 | }; 60 | }()); 61 | 62 | exports.bfs = bfs; 63 | 64 | }((typeof window === 'undefined') ? module.exports : window)); 65 | -------------------------------------------------------------------------------- /src/graphs/searching/dfs.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var dfs = (function () { 5 | 6 | function hasPath(graph, current, goal) { 7 | var stack = []; 8 | var visited = []; 9 | var node; 10 | stack.push(current); 11 | visited[current] = true; 12 | while (stack.length) { 13 | node = stack.pop(); 14 | if (node === goal) { 15 | return true; 16 | } 17 | for (var i = 0; i < graph[node].length; i += 1) { 18 | if (graph[node][i] && !visited[i]) { 19 | stack.push(i); 20 | visited[i] = true; 21 | } 22 | } 23 | } 24 | return false; 25 | } 26 | 27 | /** 28 | * Depth-First graph searching algorithm. 29 | * Returns whether there's a path between two nodes in a graph.

30 | * Time complexity: O(|V|^2). 31 | * 32 | * @module graphs/searching/dfs 33 | * @public 34 | * @param {Array} graph Adjacency matrix, which represents the graph. 35 | * @param {Number} start Start node. 36 | * @param {Number} goal Target node. 37 | * @return {Boolean} Returns true if path between two nodes exists. 38 | * 39 | * @example 40 | * var dfs = require('../src/graphs/searching/dfs').dfs; 41 | * var graph = [[1, 1, 0, 0, 1, 0], 42 | * [1, 0, 1, 0, 1, 0], 43 | * [0, 1, 0, 1, 0, 0], 44 | * [0, 0, 1, 0, 1, 1], 45 | * [1, 1, 0, 1, 0, 0], 46 | * [0, 0, 0, 1, 0, 0]]; 47 | * var pathExists = dfs(graph, 1, 5); // true 48 | */ 49 | return function (graph, start, goal) { 50 | return hasPath(graph, start, goal); 51 | }; 52 | }()); 53 | 54 | exports.dfs = dfs; 55 | 56 | }(typeof exports === 'undefined' ? window : exports)); 57 | -------------------------------------------------------------------------------- /src/graphs/shortest-path/bellman-ford.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bellman–Ford algorithm computes shortest paths from a single source 3 | * vertex to all of the other vertices in a weighted digraph 4 | * (negative weights allowed).

5 | * Time complexity: O(|V||E|) where V and E are the number of 6 | * vertices and edges respectively. 7 | * 8 | * @example 9 | * 10 | * var BellmanFord = 11 | * require('path-to-algorithms/src/graphs/shortest-path/bellman-ford'); 12 | * var Edge = BellmanFord.Edge; 13 | * var bellmanFord = BellmanFord.bellmanFord; 14 | * var edges = []; 15 | * var vertexes = [ 16 | * new Vertex(0), 17 | * new Vertex(1), 18 | * new Vertex(2), 19 | * new Vertex(3), 20 | * new Vertex(4) 21 | * ]; 22 | * 23 | * edges.push(new Edge(0, 1, -1)); 24 | * edges.push(new Edge(0, 2, 4)); 25 | * edges.push(new Edge(1, 2, 3)); 26 | * edges.push(new Edge(1, 3, 2)); 27 | * edges.push(new Edge(3, 1, 1)); 28 | * edges.push(new Edge(4, 3, -3)); 29 | * edges.push(new Edge(1, 4, 2)); 30 | * edges.push(new Edge(3, 2, 5)); 31 | * 32 | * // { 33 | * // parents: { '0': null, '1': 0, '2': 1, '3': 4, '4': 1 }, 34 | * // distances: { '0': 0, '1': -1, '2': 2, '3': -2, '4': 1 } 35 | * // } 36 | * var pathInfo = bellmanFord(vertexes, edges, 0); 37 | * 38 | * @module graphs/shortest-path/bellman-ford 39 | */ 40 | (function (exports) { 41 | 42 | 'use strict'; 43 | 44 | exports.Vertex = require('../../data-structures/vertex').Vertex; 45 | exports.Edge = require('../../data-structures/edge').Edge; 46 | 47 | /** 48 | * Computes shortest paths from a single source 49 | * vertex to all of the other vertices. 50 | * 51 | * @public 52 | * @param {Array} vertexes Vertices of the graph. 53 | * @param {Array} edges Edges of the graph. 54 | * @param {Number} source Start vertex. 55 | * @returns {Object} Object with two arrays (parents and distances) 56 | * with shortest-path information or undefined if the graph 57 | * has a negative cycle. 58 | */ 59 | exports.bellmanFord = function (vertexes, edges, source) { 60 | var distances = {}; 61 | var parents = {}; 62 | var c; 63 | if (source) { 64 | for (var i = 0; i < vertexes.length; i += 1) { 65 | distances[vertexes[i].id] = Infinity; 66 | parents[vertexes[i].id] = null; 67 | } 68 | distances[source.id] = 0; 69 | for (i = 0; i < vertexes.length - 1; i += 1) { 70 | for (var j = 0; j < edges.length; j += 1) { 71 | c = edges[j]; 72 | if (distances[c.from.id] + c.distance < distances[c.to.id]) { 73 | distances[c.to.id] = distances[c.from.id] + c.distance; 74 | parents[c.to.id] = c.from.id; 75 | } 76 | } 77 | } 78 | 79 | for (i = 0; i < edges.length; i += 1) { 80 | c = edges[i]; 81 | if (distances[c.from.id] + c.distance < distances[c.to.id]) { 82 | return undefined; 83 | } 84 | } 85 | } 86 | 87 | return { parents: parents, distances: distances }; 88 | }; 89 | 90 | })(typeof window === 'undefined' ? module.exports : window); 91 | -------------------------------------------------------------------------------- /src/graphs/shortest-path/floyd-warshall.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var floydWarshall = (function () { 5 | 6 | /** 7 | * Matrix used for the algorithm. 8 | */ 9 | var dist; 10 | 11 | /** 12 | * Initialize the distance matrix. 13 | * 14 | * @private 15 | * @param {Array} graph Distance matrix of the array. 16 | * @return {Array} Distance matrix used for the algorithm. 17 | */ 18 | function init(graph) { 19 | var dist = []; 20 | var size = graph.length; 21 | for (var i = 0; i < size; i += 1) { 22 | dist[i] = []; 23 | for (var j = 0; j < size; j += 1) { 24 | if (i === j) { 25 | dist[i][j] = 0; 26 | } else if (!isFinite(graph[i][j])) { 27 | dist[i][j] = Infinity; 28 | } else { 29 | dist[i][j] = graph[i][j]; 30 | } 31 | } 32 | } 33 | return dist; 34 | } 35 | 36 | /** 37 | * Floyd-Warshall algorithm. Finds the shortest path between 38 | * each two vertices.

39 | * Complexity: O(|V|^3) where V is the number of vertices. 40 | * 41 | * @public 42 | * @module graphs/shortest-path/floyd-warshall 43 | * @param {Array} graph A distance matrix of the graph. 44 | * @return {Array} Array which contains the shortest 45 | * distance between each two vertices. 46 | * 47 | * @example 48 | * var floydWarshall = 49 | * require('path-to-algorithms/src/graphs/shortest-path/floyd-warshall').floydWarshall; 50 | * var distMatrix = 51 | * [[Infinity, 7, 9, Infinity, Infinity, 16], 52 | * [7, Infinity, 10, 15, Infinity, Infinity], 53 | * [9, 10, Infinity, 11, Infinity, 2], 54 | * [Infinity, 15, 11, Infinity, 6, Infinity], 55 | * [Infinity, Infinity, Infinity, 6, Infinity, 9], 56 | * [16, Infinity, 2, Infinity, 9, Infinity]]; 57 | * 58 | * // [ [ 0, 7, 9, 20, 20, 11 ], 59 | * // [ 7, 0, 10, 15, 21, 12 ], 60 | * // [ 9, 10, 0, 11, 11, 2 ], 61 | * // [ 20, 15, 11, 0, 6, 13 ], 62 | * // [ 20, 21, 11, 6, 0, 9 ], 63 | * // [ 11, 12, 2, 13, 9, 0 ] ] 64 | * var shortestDists = floydWarshall(distMatrix); 65 | */ 66 | return function (graph) { 67 | dist = init(graph); 68 | var size = graph.length; 69 | for (var k = 0; k < size; k += 1) { 70 | for (var i = 0; i < size; i += 1) { 71 | for (var j = 0; j < size; j += 1) { 72 | if (dist[i][j] > dist[i][k] + dist[k][j]) { 73 | dist[i][j] = dist[i][k] + dist[k][j]; 74 | } 75 | } 76 | } 77 | } 78 | return dist; 79 | }; 80 | }()); 81 | 82 | exports.floydWarshall = floydWarshall; 83 | 84 | })(typeof window === 'undefined' ? module.exports : window); 85 | -------------------------------------------------------------------------------- /src/graphs/spanning-trees/kruskal.js: -------------------------------------------------------------------------------- 1 | // Kruskal's algorithm for minimal spanning tree implemented with the UnionFind datastructure. 2 | 3 | (function(exports) { 4 | 'use strict'; 5 | 6 | var QuickUnion = require('../../sets/quickunion').QuickUnion; 7 | var mergeSort = require('../../sorting/mergesort').mergeSort; 8 | exports.Vertex = require('../../data-structures/vertex').Vertex; 9 | exports.Edge = require('../../data-structures/edge').Edge; 10 | 11 | exports.Graph = function (edges) { 12 | this.edges = edges || []; 13 | } 14 | 15 | exports.Graph.prototype.kruskal = (function () { 16 | var qunion; 17 | var spanningTree; 18 | var indexes; 19 | 20 | /** 21 | * Used for sorting the edges 22 | * 23 | * @private 24 | * @param {Vertex} a First operand of the comparison. 25 | * @param {Vertex} b Second operand of the comparison. 26 | * @return {number} Number which which is equal, greater or 27 | * less then zero and indicates whether the first vertex is 28 | * "smaller" than the second. 29 | */ 30 | function compareEdges(a, b) { 31 | return a.distance - b.distance; 32 | } 33 | 34 | /** 35 | * Initialize the algorithm. 36 | * 37 | * @private 38 | */ 39 | function init() { 40 | var edge; 41 | var i = 0; 42 | 43 | mergeSort(this.edges, compareEdges); 44 | spanningTree = []; 45 | indexes = {}; 46 | 47 | // Create links from vertices to QuickUnion elements 48 | for (edge of this.edges) { 49 | if (!(edge.from.id in indexes)) { 50 | indexes[edge.from.id] = i; 51 | i += 1; 52 | } 53 | if (!(edge.to.id in indexes)) { 54 | indexes[edge.to.id] = i; 55 | i += 1; 56 | } 57 | } 58 | 59 | qunion = new QuickUnion(i); 60 | } 61 | 62 | return function () { 63 | init.call(this); 64 | 65 | var edge; 66 | 67 | for (edge of this.edges) { 68 | var from = indexes[edge.from.id]; 69 | var to = indexes[edge.to.id]; 70 | if (!qunion.connected(from, to)) { 71 | qunion.union(from, to); 72 | spanningTree.push(edge); 73 | } 74 | } 75 | 76 | return new exports.Graph(spanningTree); 77 | } 78 | 79 | })(); 80 | 81 | })(typeof window === 'undefined' ? module.exports : window); 82 | -------------------------------------------------------------------------------- /src/others/fibonacci.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Nth number of fibonacci's sequence 3 | * 4 | * Returns the nth number of fibonacci's sequence. 5 | * 6 | * @public 7 | * 8 | * @example 9 | * var fibonacci = require('path-to-algorithms/src/others/fibonacci').fibonacci; 10 | * var nth = fibonacci(20); 11 | * 12 | * console.log(nth); // 6765 13 | * 14 | * @param {Number} n The nth position in fibonacci's sequence 15 | * 16 | * @module others/fibonacci 17 | */ 18 | (function (exports) { 19 | 'use strict'; 20 | 21 | function fibonacci(n) { 22 | if (n > 97) { 23 | throw 'Input too large, results in inaccurate fibonacci value.'; 24 | } 25 | var n1 = 0; 26 | var n2 = 1; 27 | var aux; 28 | 29 | while (n > 0) { 30 | aux = n1; 31 | n1 = n2; 32 | n2 += aux; 33 | n = n - 1; 34 | } 35 | 36 | return n1; 37 | } 38 | 39 | exports.fibonacci = fibonacci; 40 | })(typeof window === 'undefined' ? module.exports : window); 41 | -------------------------------------------------------------------------------- /src/others/fibonacciMemory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Nth number of fibonacciMemory's sequence 3 | * 4 | * Returns the nth number of fibonacciMemory's sequence. 5 | * 6 | * @public 7 | * 8 | * @example 9 | * var fibonacciMemory = require('path-to-algorithms/src/others/fibonacciMemory').fibonacciMemory; 10 | * var nth = fibonacciMemory(20); 11 | * 12 | * console.log(nth); // 6765 13 | * 14 | * @param {Number} n The nth position in fibonacciMemory's sequence 15 | * 16 | * @module others/fibonacciMemory 17 | */ 18 | (function (exports) { 19 | 'use strict'; 20 | 21 | function fibonacciMemory(n) { 22 | var i = 0; 23 | var aux = [0, 1]; 24 | while (n !== i) { 25 | aux[i + 2] = aux[i] + aux[i + 1]; 26 | i += 1; 27 | } 28 | return aux[i]; 29 | } 30 | 31 | exports.fibonacciMemory = fibonacciMemory; 32 | })(typeof window === 'undefined' ? module.exports : window); 33 | -------------------------------------------------------------------------------- /src/others/hanoi.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Returns all movements needed to solve Hanoi Tower problem. 6 | * 7 | * @public 8 | * @module others/hanoi 9 | * 10 | * @example 11 | * 12 | * var hanoi = require('path-to-algorithms/src/others/hanoi').hanoi; 13 | * var movements = hanoi(3, 'a', 'b', 'c'); 14 | * 15 | * // Move a to c 16 | * // Move a to b 17 | * // Move c to b 18 | * // Move a to c 19 | * // Move b to a 20 | * // Move b to c 21 | * // Move a to c 22 | * movements.forEach(function (move) { 23 | * console.log('Move', move[0], 'to', move[1]); 24 | * }); 25 | * 26 | * @param {Number} count Count of the plates/stones. 27 | * @param {String|Number} source Identifier of the 1st peg. 28 | * @param {String|Number} intermediate Identifier of the 2nd peg. 29 | * @param {String|Number} goal Identifier of the 3rd peg. 30 | * @return Array which contains all the moves required 31 | * in order to place all the plates onto the last peg. 32 | */ 33 | function hanoi(count, source, intermediate, goal, result) { 34 | result = result || []; 35 | if (count === 1) { 36 | result.push([source, goal]); 37 | } else { 38 | hanoi(count - 1, source, goal, intermediate, result); 39 | result.push([source, goal]); 40 | hanoi(count - 1, intermediate, source, goal, result); 41 | } 42 | return result; 43 | } 44 | 45 | exports.hanoi = hanoi; 46 | 47 | })(typeof window === 'undefined' ? module.exports : window); 48 | -------------------------------------------------------------------------------- /src/others/levenshtein-distance.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var levenshteinDistance = (function () { 5 | 6 | function levenshteinDistance (s, ls, t, lt) { 7 | var memo = []; 8 | var currRowMemo; 9 | var i; 10 | var k; 11 | 12 | for (k = 0; k <= lt; k += 1) { 13 | memo[k] = k; 14 | } 15 | 16 | for (i = 1; i <= ls; i += 1) { 17 | currRowMemo = [i]; 18 | 19 | for (k = 1; k <= lt; k += 1) { 20 | currRowMemo[k] = Math.min( 21 | currRowMemo[k - 1] + 1, 22 | memo[k] + 1, 23 | memo[k - 1] + (s[i - 1] !== t[k - 1] ? 1 : 0) 24 | ); 25 | } 26 | 27 | memo = currRowMemo; 28 | } 29 | 30 | return memo[lt]; 31 | } 32 | 33 | /** 34 | * The Levenshtein distance between two strings is a minimum number 35 | * of edits needed to transform one string into the other, with the 36 | * allowable edit operations being insertion, deletion, 37 | * or substitution of a single character. 38 | * 39 | * @public 40 | * @module others/levenshtein-distance 41 | * 42 | * @example 43 | * 44 | * var dist = require('path-to-algorithms/src/others/' + 45 | * 'levenshtein-distance').levenshteinDistance; 46 | * console.log(dist('kitten', 'sitting')); // 3 47 | * 48 | * @param {String} s Source string. 49 | * @param {String} t Target string. 50 | * @return {Number} Minimum number of edits needed 51 | * to transform source string into the target string. 52 | */ 53 | return function (s, t) { 54 | return levenshteinDistance(s, s.length, t, t.length); 55 | }; 56 | }()); 57 | 58 | exports.levenshteinDistance = levenshteinDistance; 59 | 60 | }(typeof exports === 'undefined' ? window : exports)); 61 | 62 | -------------------------------------------------------------------------------- /src/others/min-coins-change.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Returns the minimum number of coins from given set, 6 | * which sum equals to given change. This is famous 7 | * problem from the dynamic programming: 8 | * {@link https://en.wikipedia.org/wiki/Change-making_problem} 9 | * 10 | * @public 11 | * @module others/minCoinsChange 12 | * 13 | * @example 14 | * 15 | * var minCoinsChange = 16 | * require('path-to-algorithms/src/others/min-coins-change') 17 | * .minCoinsChange; 18 | * var coins = minCoinsChange([1, 2, 3], 5); // [ 2, 3 ] 19 | * 20 | * @param {Array} coins The sorted list of the coins used for the change. 21 | * @param {Number} change The change, which should be returned. 22 | * @return Array which contains the minimum coins from the given 23 | * list, required for the change. 24 | */ 25 | function minCoinsChange(coins, change) { 26 | var minChange = [[0]]; 27 | if (coins.indexOf(change) >= 0) { 28 | return [change]; 29 | } 30 | for (var i = 1; i <= change; i += 1) { 31 | for (var j = 0; j < coins.length && coins[j] <= change; j += 1) { 32 | for (var k = 0; k < minChange.length; k += 1) { 33 | if (k + coins[j] === i) { 34 | minChange[i] = minChange[k].concat([coins[j]]); 35 | } 36 | } 37 | } 38 | } 39 | var result = minChange[change]; 40 | if (!result) { 41 | return undefined; 42 | } 43 | return result.slice(1); 44 | } 45 | 46 | exports.minCoinsChange = minCoinsChange; 47 | 48 | })(typeof window === 'undefined' ? module.exports : window); 49 | -------------------------------------------------------------------------------- /src/others/minimax.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | /* eslint max-params: 0 */ 4 | 5 | /** 6 | * @param {Function} getPossibleNextStatesFn Function which returns all possible next moves with states . 7 | * @param {Function} isGameOverFn Function which returns if game is over. 8 | * @param {Function} getScoreFn Function which returns score. 9 | * @return {Function} minimax function 10 | */ 11 | function minimaxBuilder( 12 | getPossibleNextStatesFn, 13 | isGameOverFn, 14 | getScoreFn 15 | ) { 16 | /** 17 | * Minimax (sometimes MinMax, MM[1] or saddle point[2]) is a decision rule used in artificial intelligence, 18 | * decision theory, game theory, statistics, and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario. 19 | * Optimized with alpha-beta pruning. 20 | * {@link https://en.wikipedia.org/wiki/Minimax} 21 | * {@link https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning} 22 | * 23 | * @public 24 | * @module others/minimax 25 | * 26 | * @example 27 | * 28 | * var miniMax = 29 | * require('path-to-algorithms/src/others/minimax').minimax; 30 | * var result = minimax( 31 | * [1, 2, 3], 32 | * true, 33 | * 5, 34 | * -Infinity, 35 | * Infinity, 36 | * state => ({ move: 0, state: [2, 3, 4] }), 37 | * state => state[1] < 3, 38 | * state => state[1] 39 | * ); 40 | * 41 | * @param {*} state Current game state 42 | * @param {Boolean} maximize Defines if the result should be maximized or minimized 43 | * @param {Number} depth Defines the maximum depth search 44 | * @param {Number} alpha Maximum score that the minimizing player is assured 45 | * @param {Number} beta Minimum score that the maximizing player is assured 46 | * @return {{score: Number, move: *}} which contains the minimum coins from the given 47 | * list, required for the change. 48 | */ 49 | const minimax = ( 50 | state, 51 | maximize, 52 | depth, 53 | alpha, 54 | beta 55 | ) => { 56 | if (depth === 0 || isGameOverFn(state)) { 57 | const score = getScoreFn(state); 58 | return {score, move: null}; 59 | } 60 | 61 | const possibleMoveResults = getPossibleNextStatesFn(state); 62 | 63 | if (maximize) { 64 | 65 | let maxResult = {score: -Infinity, move: null}; 66 | 67 | for (const next of possibleMoveResults) { 68 | const result = minimax( 69 | next.state, 70 | false, 71 | depth - 1, 72 | alpha, 73 | beta 74 | ); 75 | 76 | if (result.score > maxResult.score) { 77 | maxResult = {score: result.score, move: next.move}; 78 | } 79 | 80 | alpha = Math.max(alpha, result.score); 81 | 82 | if (alpha >= beta) { 83 | break; 84 | } 85 | } 86 | 87 | return maxResult; 88 | } else { 89 | let minResult = {score: Infinity, move: null}; 90 | 91 | for (const next of possibleMoveResults) { 92 | const result = minimax( 93 | next.state, 94 | true, 95 | depth - 1, 96 | alpha, 97 | beta 98 | ); 99 | 100 | if (result.score < minResult.score) { 101 | minResult = {score: result.score, move: next.move}; 102 | } 103 | 104 | beta = Math.min(beta, result.score); 105 | 106 | if (beta <= alpha) { 107 | break; 108 | } 109 | } 110 | 111 | return minResult; 112 | } 113 | } 114 | 115 | return minimax; 116 | } 117 | 118 | exports.minimaxBuilder = minimaxBuilder; 119 | 120 | })(typeof window === 'undefined' ? module.exports : window); 121 | -------------------------------------------------------------------------------- /src/others/minkowski-distance.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var minkowskiDistance = (function () { 5 | 6 | function chebyshevDistance (x, y, lx, p, mathfn) { 7 | var ret = -p; 8 | var i; 9 | 10 | for (i = 0; i < lx; i += 1) { 11 | ret = mathfn(ret, Math.abs(x[i] - y[i])); 12 | } 13 | 14 | return ret; 15 | } 16 | 17 | function minkowskiDistance (x, lx, y, ly, p) { 18 | var d; 19 | var i; 20 | 21 | if (lx !== ly) { 22 | throw 'Both vectors should have same dimension'; 23 | } 24 | 25 | if (isNaN(p)) { 26 | throw 'The order "p" must be a number'; 27 | } 28 | 29 | if (p === Number.POSITIVE_INFINITY) { 30 | return chebyshevDistance(x, y, lx, p, Math.max); 31 | } else if (p === Number.NEGATIVE_INFINITY) { 32 | return chebyshevDistance(x, y, lx, p, Math.min); 33 | } else if (p < 1) { 34 | throw 'Order less than 1 will violate the triangle inequality'; 35 | } else { 36 | d = 0; 37 | 38 | for (i = 0; i < lx; i += 1) { 39 | d += Math.pow(Math.abs(x[i] - y[i]), p); 40 | } 41 | 42 | return isNaN(d) 43 | ? 0 44 | : Math.pow(d, 1 / p); 45 | 46 | } 47 | 48 | } 49 | 50 | /** 51 | * The Minkowski distance between two points gets generalized 52 | * metric distance 53 | * when p === 1, this becomes same as Manhattan Distance 54 | * when p === 2, this becomes same as Euclidean Distance 55 | * when p === Positive or Negative Infinity, 56 | * this becomes chebyshev distance 57 | * 58 | * @public 59 | * @module others/minkowski-distance 60 | * 61 | * @example 62 | * var dist = require('path-to-algorithms/src/others/' + 63 | * 'minkowski-distance').minkowskiDistance; 64 | * console.log(dist([0, 1], [1, 1], 2)); // 1 65 | * 66 | * @param {Array} x source point 67 | * @param {Array} y target point 68 | * @param {Number} p order of Minkowski distance 69 | * @returns {Number} distance between two points, if distance 70 | * is NaN, then this returns 0 71 | */ 72 | return function (x, y, p) { 73 | return minkowskiDistance (x, x.length, y, y.length, p); 74 | }; 75 | }()); 76 | 77 | exports.minkowskiDistance = minkowskiDistance; 78 | 79 | }(typeof exports === 'undefined' ? window : exports)); 80 | -------------------------------------------------------------------------------- /src/primes/is-prime.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Advanced (optimised) method for checking if provided number is prime. 6 | * For example for number 104743 it should return true, for 104744 - false. 7 | * 8 | * @module primes/is-prime 9 | * @param {Number} number - Number that we check on prime. 10 | * @returns {Boolean} Will return true if provided number is prime. 11 | * 12 | * @example 13 | * var isPrime = require('path-to-algorithms/src/is-prime').isPrime; 14 | * 15 | * console.log(isPrime(7)); // true 16 | * console.log(isPrime(18)); // false 17 | */ 18 | exports.isPrime = function (number) { 19 | 20 | if (number < 2) { 21 | return false; 22 | } 23 | 24 | if (number % 2 === 0) { 25 | return (number === 2); 26 | } 27 | 28 | if (number % 3 === 0) { 29 | return (number === 3); 30 | } 31 | 32 | var horizon = Math.floor(Math.sqrt(number)); 33 | var factor = 5; 34 | 35 | while (factor <= horizon) { 36 | 37 | if (number % factor === 0) { 38 | return false; 39 | } 40 | 41 | if (number % (factor + 2) === 0) { 42 | return false; 43 | } 44 | factor += 6; 45 | } 46 | return true; 47 | }; 48 | 49 | }(typeof exports === 'undefined' ? window : exports)); 50 | -------------------------------------------------------------------------------- /src/primes/prime-factor-tree.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Method will return list of all primes for provided number. 6 | * For example for number 18 it should return following list of primes 7 | * [2, 3, 3]. 8 | * 9 | * @module primes/prime-factor-tree 10 | * @param {Number} number - Number for which method will find all primes. 11 | * @returns {Array} List of available primes for provided number. 12 | * 13 | * @example 14 | * var primeFactorTree = require('path-to-algorithms/src/prime-factor-tree') 15 | * .primeFactorTree; 16 | * 17 | * console.log(primeFactorTree(18)); // [2, 3, 3] 18 | * console.log(primeFactorTree(600851475143)); // [71, 839, 1471, 6857] 19 | */ 20 | exports.primeFactorTree = function (number) { 21 | var array = []; 22 | var s = 6; 23 | while (number > 1 && number % 2 === 0) { 24 | number /= 2; 25 | array.push(2); 26 | } 27 | while (number > 2 && number % 3 === 0) { 28 | number /= 3; 29 | array.push(3); 30 | } 31 | while (number > 4) { 32 | var p = s - 1; 33 | var q = s + 1; 34 | while (number > 4 && number % p === 0) { 35 | number /= p; 36 | array.push(p); 37 | } 38 | while (number > 4 && number % q === 0) { 39 | number /= q; 40 | array.push(q); 41 | } 42 | s += 6; 43 | } 44 | return array; 45 | }; 46 | 47 | }(typeof exports === 'undefined' ? window : exports)); 48 | -------------------------------------------------------------------------------- /src/primes/sieve-of-atkins.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Sieve of Atkins. 6 | * 7 | * Modern algorithm for finding all prime numbers up to a specified integer. 8 | * 9 | * Returns list of primes up to specified limit. 10 | * 11 | * For example, for limit 10 it should return following list of primes: 12 | * [2, 3, 5, 7]. 13 | * 14 | * @module primes/sieve-of-atkins 15 | * @param {Number} limit - Algorithm will returns list of primes up to 16 | * specified limit. 17 | * @returns {Array} Will return list with all prime numbers up to provided. 18 | * limit. 19 | * 20 | * @example 21 | * var sieveOfAtkins = 22 | * require('path-to-algorithms/src/sieve-of-atkins').sieveOfAtkins; 23 | * 24 | * console.log(sieveOfAtkins(12)); // [2, 3, 5, 7, 11] 25 | */ 26 | exports.sieveOfAtkins = function (limit) { 27 | if (limit <= 1) { 28 | return []; 29 | } 30 | 31 | const sieve = Array(limit + 1); 32 | 33 | const testingLimit = Math.ceil(Math.sqrt(limit)); 34 | 35 | var i; 36 | var j; 37 | var n; 38 | 39 | for (i = 1; i < testingLimit; i += 1) { 40 | var ii = i * i; 41 | for (j = 1; j < testingLimit; j += 1) { 42 | var jj = j * j; 43 | if (ii + jj >= limit) { 44 | break; 45 | } 46 | 47 | n = 4 * ii + jj; 48 | if (n <= limit && (n % 12 === 1 || n % 12 === 5)) { 49 | sieve[n] = !sieve[n]; 50 | } 51 | 52 | n = 3 * ii + jj; 53 | if (n <= limit && (n % 12 === 7)) { 54 | sieve[n] = !sieve[n]; 55 | } 56 | 57 | n = 3 * ii - jj; 58 | if (i > j && n <= limit && (n % 12 === 11)) { 59 | sieve[n] = !sieve[n]; 60 | } 61 | } 62 | } 63 | 64 | for (n = 5; n <= testingLimit; n += 1) { 65 | if (sieve[n]) { 66 | j = n * n; 67 | for (i = j; i <= limit; i += j) { 68 | sieve[i] = false; 69 | } 70 | } 71 | } 72 | 73 | const primes = [2]; 74 | 75 | if (limit > 2) { 76 | primes.push(3); 77 | } 78 | 79 | sieve.forEach(function (value, key) { 80 | if (value) { 81 | this.push(key); 82 | } 83 | }, primes); 84 | 85 | return primes; 86 | } 87 | }(typeof exports === 'undefined' ? window : exports)); 88 | -------------------------------------------------------------------------------- /src/primes/sieve-of-eratosthenes.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Sieve of Eratosthenes. 6 | * 7 | * Simple, ancient algorithm for finding all prime numbers up to given limit. 8 | * 9 | * Returns list of primes up to specified limit. 10 | * 11 | * For example, for limit 10 it should return following list of primes: 12 | * [2, 3, 5, 7]. 13 | * 14 | * @module primes/sieve-of-eratosthenes 15 | * @param {Number} limit - Algorithm will returns list of primes up to 16 | * specified limit. 17 | * @returns {Array} Will return list with all prime numbers up to provided. 18 | * limit. 19 | * 20 | * @example 21 | * var sieveOfEratosthenes = 22 | * require('path-to-algorithms/src/sieve-of-eratosthenes').sieveOfEratosthenes; 23 | * 24 | * console.log(sieveOfEratosthenes(12)); // [2, 3, 5, 7, 11] 25 | */ 26 | exports.sieveOfEratosthenes = function (limit) { 27 | var sieve = []; 28 | var primes = []; 29 | var k; 30 | var l; 31 | 32 | sieve[1] = false; 33 | 34 | for (k = 2; k <= limit; k += 1) { 35 | sieve[k] = true; 36 | } 37 | 38 | for (k = 2; k * k <= limit; k += 1) { 39 | if (sieve[k] !== true) { 40 | continue; 41 | } 42 | 43 | for (l = k * k; l <= limit; l += k) { 44 | sieve[l] = false; 45 | } 46 | } 47 | 48 | sieve.forEach(function (value, key) { 49 | if (value) { 50 | this.push(key); 51 | } 52 | }, primes); 53 | 54 | return primes; 55 | }; 56 | 57 | }(typeof exports === 'undefined' ? window : exports)); 58 | -------------------------------------------------------------------------------- /src/searching/binarysearch.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function id (val) { return val; } 5 | function get (key) { return function (val) { return val[key]; }; } 6 | 7 | /** 8 | * Searches for specific element in a given array using 9 | * the binary search algorithm.

10 | * Time complexity: O(log N). 11 | * 12 | * @example 13 | * 14 | * var search = require('path-to-algorithms/src/searching/'+ 15 | * 'binarysearch').binarySearch; 16 | * console.log(search([1, 2, 3, 4, 5], 4)); // 3 17 | * 18 | * @public 19 | * @module searching/binarysearch 20 | * @param {Array} array Input array. 21 | * @param {Number} value Value of the element which index should be found. 22 | * @returns {Number} Index of the element or -1 if not found. 23 | */ 24 | function binarySearch(array, value, key) { 25 | key = !key ? id : typeof key === 'string' ? get(key) : key; 26 | value = key(value); 27 | var middle = Math.floor(array.length / 2); 28 | var left = 0; 29 | var right = array.length; 30 | while (right >= left) { 31 | var middleValue = key(array[middle]); 32 | if (middleValue === value) { 33 | return middle; 34 | } else if (middleValue > value) { 35 | right = middle - 1; 36 | } else { 37 | left = middle + 1; 38 | } 39 | middle = Math.floor((left + right) / 2); 40 | } 41 | return -1; 42 | } 43 | 44 | exports.binarySearch = binarySearch; 45 | 46 | })(typeof window === 'undefined' ? module.exports : window); 47 | -------------------------------------------------------------------------------- /src/searching/interpolation-search.js: -------------------------------------------------------------------------------- 1 | (function(exports) { 2 | 'use strict'; 3 | /** 4 | * Searches for specific element in a given array using 5 | * the interpolation search algorithm.

6 | * Time complexity: O(log log N) when elements are uniformly 7 | * distributed, and O(N) in the worst case 8 | * 9 | * @example 10 | * 11 | * var search = require('path-to-algorithms/src/searching/'+ 12 | * 'interpolation-search').interpolationSearch; 13 | * console.log(search([1, 2, 3, 4, 5], 4)); // 3 14 | * 15 | * @public 16 | * @module searching/interpolation-search 17 | * @param {Array} sortedArray Input array. 18 | * @param {Number} seekIndex of the element which index should be found. 19 | * @returns {Number} Index of the element or -1 if not found. 20 | */ 21 | function interpolationSearch(sortedArray, seekIndex) { 22 | let leftIndex = 0; 23 | let rightIndex = sortedArray.length - 1; 24 | 25 | while (leftIndex <= rightIndex) { 26 | const rangeDiff = sortedArray[rightIndex] - sortedArray[leftIndex]; 27 | const indexDiff = rightIndex - leftIndex; 28 | const valueDiff = seekIndex - sortedArray[leftIndex]; 29 | 30 | if (valueDiff < 0) { 31 | return -1; 32 | } 33 | 34 | if (!rangeDiff) { 35 | return sortedArray[leftIndex] === seekIndex ? leftIndex : -1; 36 | } 37 | 38 | const middleIndex = 39 | leftIndex + Math.floor((valueDiff * indexDiff) / rangeDiff); 40 | 41 | if (sortedArray[middleIndex] === seekIndex) { 42 | return middleIndex; 43 | } 44 | 45 | if (sortedArray[middleIndex] < seekIndex) { 46 | leftIndex = middleIndex + 1; 47 | } else { 48 | rightIndex = middleIndex - 1; 49 | } 50 | } 51 | 52 | return -1; 53 | } 54 | exports.interpolationSearch = interpolationSearch; 55 | })(typeof window === 'undefined' ? module.exports : window); 56 | -------------------------------------------------------------------------------- /src/searching/jump-search.js: -------------------------------------------------------------------------------- 1 | (function(exports) { 2 | 'use strict'; 3 | /** 4 | * Searches for specific element in a given array using 5 | * the jump search algorithm.

6 | * Time complexity: O(log N). 7 | * 8 | * @example 9 | * 10 | * var search = require('path-to-algorithms/src/searching/'+ 11 | * 'jump-search').jumpSearch; 12 | * console.log(search([1, 2, 3, 4, 5], 4)); // 3 13 | * 14 | * @public 15 | * @module searching/jumpsearch 16 | * @param {Array} sortedArray Input array. 17 | * @param {Number} seekIndex of the element which index should be found. 18 | * @returns {Number} Index of the element or -1 if not found. 19 | */ 20 | function jumpSearch(sortedArray, seekIndex) { 21 | // exit if array empty 22 | const arrayLength = sortedArray.length; 23 | if (!arrayLength) { 24 | return -1; 25 | } 26 | 27 | // set jumpSize 28 | const jumpSize = Math.floor(Math.sqrt(arrayLength)); 29 | 30 | let blockStart = 0; 31 | let blockEnd = jumpSize; 32 | 33 | while (seekIndex > sortedArray[Math.min(blockEnd, arrayLength) - 1]) { 34 | blockStart = blockEnd; 35 | blockEnd += jumpSize; 36 | 37 | // if out of array bounds exit 38 | if (blockStart > arrayLength) { 39 | return -1; 40 | } 41 | } 42 | 43 | let currentIndex = blockStart; 44 | while (currentIndex < Math.min(blockEnd, arrayLength)) { 45 | if (sortedArray[currentIndex] === seekIndex) { 46 | return currentIndex; 47 | } 48 | 49 | currentIndex += 1; 50 | } 51 | 52 | return -1; 53 | } 54 | 55 | exports.jumpSearch = jumpSearch; 56 | })(typeof window === 'undefined' ? module.exports : window); 57 | -------------------------------------------------------------------------------- /src/searching/knuth-morris-pratt.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var kmp = (function () { 5 | function builtKMPTable(str) { 6 | var res = []; 7 | var len; 8 | var front; 9 | var end; 10 | var found; 11 | for (var i = 1; i <= str.length; i += 1) { 12 | front = Math.max(1, i - ((res[i - 2] || 0) + 1)); 13 | end = Math.min(i - 1, (res[i - 2] || 0) + 1); 14 | found = false; 15 | len = 0; 16 | while (end >= 1 && front <= i && !found) { 17 | if (str.substring(0, end) === str.substring(front, i)) { 18 | found = true; 19 | len = end; 20 | } else { 21 | end -= 1; 22 | front += 1; 23 | } 24 | } 25 | res[i - 1] = len; 26 | } 27 | return res; 28 | } 29 | 30 | /** 31 | * Knuth–Morris–Pratt algorithm. Searches for the position of 32 | * the first occurrence of a specified value in a string. 33 | * 34 | * @example 35 | * 36 | * var indexOf = require('path-to-algorithm/src/searching/'+ 37 | * 'knuth-morris-pratt').kmp; 38 | * console.log(indexOf('hello', 'll')); // 2 39 | * 40 | * @public 41 | * @module searching/knuth-morris-pratt 42 | * @param {String} str String. 43 | * @param {String} substr Substring. 44 | * @return {Number} A Number, representing the position 45 | * where the specified substring occurs for the first 46 | * time, or -1 if it never occurs. 47 | */ 48 | function indexOf(str, substr) { 49 | if (str === substr) { 50 | return 0; 51 | } 52 | var table = builtKMPTable(substr); 53 | var i = 0; 54 | var j = 0; 55 | while (i < str.length) { 56 | if (str[i] === substr[j]) { 57 | i += 1; 58 | j += 1; 59 | } 60 | if (j === substr.length) { 61 | return i - j; 62 | } 63 | if (i < str.length && str[i] !== substr[j]) { 64 | if (j > 0 && table[j - 1] !== 0) { 65 | j = table[j - 1]; 66 | } else { 67 | i += 1; 68 | j = 0; 69 | } 70 | } 71 | } 72 | return -1; 73 | } 74 | return indexOf; 75 | }()); 76 | 77 | exports.kmp = kmp; 78 | 79 | })(typeof window === 'undefined' ? module.exports : window); 80 | -------------------------------------------------------------------------------- /src/searching/linearSearch.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Searches for specific element in a given array 6 | * using the linear search algorithm 7 | * Time complexity: O(n) 8 | * 9 | * @param {Array} array Input array 10 | * @param {Number} key the number whose index is to be found 11 | * @returns {Number} the index of the first instance of number or else -1 if not found 12 | */ 13 | 14 | const linearSearch = (array, key) => { 15 | for (let i = 0; i < array.length; i += 1) { 16 | if (array[i] === key) { 17 | return i; 18 | } 19 | } 20 | return -1; 21 | }; 22 | 23 | exports.linearSearch = linearSearch; 24 | })(typeof window === 'undefined' ? module.exports : window); 25 | -------------------------------------------------------------------------------- /src/searching/longest-common-subsequence.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | exports.longestCommonSubsequence = (function () { 5 | 6 | /** 7 | * Find the lengths of longest common sub-sequences 8 | * of two strings and their substrings. 9 | * 10 | * Complexity: O(MN). 11 | * 12 | * @private 13 | * @param {String} first string 14 | * @param {String} second string 15 | * @return {Array} two dimensional array with LCS 16 | * lengths of input strings and their substrings. 17 | * 18 | */ 19 | function getLcsLengths(str1, str2) { 20 | var result = []; 21 | for (var i = -1; i < str1.length; i = i + 1) { 22 | result[i] = []; 23 | for (var j = -1; j < str2.length; j = j + 1) { 24 | if (i === -1 || j === -1) { 25 | result[i][j] = 0; 26 | } else if (str1[i] === str2[j]) { 27 | result[i][j] = result[i - 1][j - 1] + 1; 28 | } else { 29 | result[i][j] = Math.max(result[i - 1][j], result[i][j - 1]); 30 | } 31 | } 32 | } 33 | return result; 34 | } 35 | 36 | /** 37 | * Find longest common sub-sequences of two strings. 38 | * 39 | * Complexity: O(M + N). 40 | * 41 | * @private 42 | * @param {String} first string 43 | * @param {String} second string 44 | * @return {Array} two dimensional array with LCS 45 | * lengths of input strings and their substrings 46 | * returned from 'getLcsLengths' function. 47 | * 48 | */ 49 | function getLcs(str1, str2, lcsLengthsMatrix) { 50 | var execute = function (i, j) { 51 | if (!lcsLengthsMatrix[i][j]) { 52 | return ''; 53 | } else if (str1[i] === str2[j]) { 54 | return execute(i - 1, j - 1) + str1[i]; 55 | } else if (lcsLengthsMatrix[i][j - 1] > lcsLengthsMatrix[i - 1][j]) { 56 | return execute(i, j - 1); 57 | } else { 58 | return execute(i - 1, j); 59 | } 60 | }; 61 | return execute(str1.length - 1, str2.length - 1); 62 | } 63 | 64 | /** 65 | * Algorithm from dynamic programming. It finds the longest 66 | * common sub-sequence of two strings. For example for strings 'abcd' 67 | * and 'axxcda' the longest common sub-sequence is 'acd'. 68 | * 69 | * @example 70 | * var subsequence = require('path-to-algorithms/src/searching/'+ 71 | * 'longest-common-subsequence').longestCommonSubsequence; 72 | * console.log(subsequence('abcd', 'axxcda'); // 'acd' 73 | * 74 | * @public 75 | * @module searching/longest-common-subsequence 76 | * @param {String} first input string. 77 | * @param {String} second input string. 78 | * @return {Array} Longest common subsequence. 79 | */ 80 | return function (str1, str2) { 81 | var lcsLengthsMatrix = getLcsLengths(str1, str2); 82 | return getLcs(str1, str2, lcsLengthsMatrix); 83 | }; 84 | })(); 85 | 86 | })(typeof window === 'undefined' ? module.exports : window); 87 | -------------------------------------------------------------------------------- /src/searching/longest-increasing-subsequence.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | exports.longestIncreasingSubsequence = (function () { 5 | 6 | /** 7 | * Find the index of the first largest element in array. 8 | * Complexity: O(N). 9 | * 10 | * @private 11 | * @param {Array} array The array in which the largest 12 | * element should be found. 13 | * @return {Number} index of the first largest element 14 | */ 15 | function max(array) { 16 | if (!array || !array.length) { 17 | return -1; 18 | } 19 | var maxIdx = 0; 20 | for (var i = 1; i < array.length; i += 1) { 21 | if (array[maxIdx].distance < array[i].distance) { 22 | maxIdx = i; 23 | } 24 | } 25 | return maxIdx; 26 | } 27 | 28 | /** 29 | * Default comparison method. 30 | * @private 31 | */ 32 | function asc(a, b) { 33 | return a - b; 34 | } 35 | 36 | /** 37 | * Creates directed graph from given array. 38 | * Each element's neighbours are the elements which can be 39 | * after the element in the resulting sequence.

40 | * Complexity: O(N^2). 41 | * @private 42 | * @param {Array} array The input array. 43 | * @param {Function} cmp Comparator. 44 | * @return {Object} Graph represented with list of neighbours. 45 | */ 46 | function buildDag(array, cmp) { 47 | var result = []; 48 | for (var i = 0; i < array.length; i += 1) { 49 | result[i] = []; 50 | for (var j = i + 1; j < array.length; j += 1) { 51 | if (cmp(array[i], array[j]) < 0) { 52 | result[i].push(j); 53 | } 54 | } 55 | } 56 | return result; 57 | } 58 | 59 | /** 60 | * Finds the longest increasing sub-sequence for given node.

61 | * Complexity: O(N^N). 62 | * @private 63 | * @param {Object} dag Graph represented with list of neighbours. 64 | * @param {number} node The current node. 65 | * @return {object} The longest increasing sub-sequence for given node. 66 | */ 67 | function find(dag, node) { 68 | node = node || 0; 69 | if (find.memo[node]) { 70 | return find.memo[node]; 71 | } 72 | var neighbours = dag[node]; 73 | var neighboursDistance = []; 74 | var maxDist; 75 | // var maxNode; 76 | var distance; 77 | var result; 78 | 79 | if (!neighbours.length) { 80 | return { distance: 1, neighbour: undefined, node: node }; 81 | } 82 | 83 | for (var i = 0; i < neighbours.length; i += 1) { 84 | neighboursDistance[i] = find(dag, neighbours[i]); 85 | } 86 | 87 | maxDist = max(neighboursDistance); 88 | // maxNode = neighbours[maxDist]; 89 | distance = 1 + neighboursDistance[maxDist].distance; 90 | find.memo[node] = result = { 91 | distance: distance, 92 | neighbour: neighboursDistance[maxDist], 93 | node: node 94 | }; 95 | return result; 96 | } 97 | 98 | /** 99 | * Algorithm from dynamic programming. It finds the longest 100 | * sub-sequence of increasing numbers. It is not required 101 | * the numbers to be neighboring. For example for 1, 5, 2 102 | * sequence the longest sub-sequence is 1, 2. 103 | * 104 | * @example 105 | * var subsequence = require('path-to-algorithms/src/searching/'+ 106 | * 'longest-increasing-subsequence').longestIncreasingSubsequence; 107 | * console.log(subsequence([1, 0, 4, 3, 5])); // 1, 4, 5 108 | * 109 | * @public 110 | * @module searching/longest-increasing-subsequence 111 | * @param {Array} array Input sequence. 112 | * @param {Function} cmp Comparator. 113 | * @return {Array} Longest increasing subsequence. 114 | */ 115 | return function (array, cmp) { 116 | cmp = cmp || asc; 117 | var results = []; 118 | var dag = buildDag(array, cmp); 119 | var maxPath; 120 | find.memo = []; 121 | for (var i = 0; i < array.length; i += 1) { 122 | results.push(find(dag, i)); 123 | } 124 | maxPath = results[max(results)]; 125 | results = []; 126 | while (maxPath) { 127 | results.push(array[maxPath.node]); 128 | maxPath = maxPath.neighbour; 129 | } 130 | return results; 131 | }; 132 | })(); 133 | 134 | })(typeof window === 'undefined' ? module.exports : window); 135 | 136 | -------------------------------------------------------------------------------- /src/searching/maximum-subarray-divide-and-conquer.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Accepts an array and range. Finds the maximum sum of elements 6 | * around the middle of the range. 7 | * @private 8 | * @param {Array} array Input array. 9 | * @param {Number} left Left interval of the range. 10 | * @param {Number} middle Middle of the range. 11 | * @param {Number} right Right side of the range. 12 | * @return {Number} The maximum sum including the middle element. 13 | */ 14 | function crossSubarray(array, left, middle, right) { 15 | var leftSum = -Infinity; 16 | var rightSum = -Infinity; 17 | var sum = 0; 18 | var i; 19 | 20 | for (i = middle; i >= left; i -= 1) { 21 | if (sum + array[i] >= leftSum) { 22 | leftSum = sum + array[i]; 23 | } 24 | sum += array[i]; 25 | } 26 | sum = 0; 27 | for (i = middle + 1; i < right; i += 1) { 28 | if (sum + array[i] >= rightSum) { 29 | rightSum = sum + array[i]; 30 | } 31 | sum += array[i]; 32 | } 33 | return leftSum + rightSum; 34 | } 35 | 36 | /** 37 | * @private 38 | * @param {Array} array Input array. 39 | * @param {Number} left Left side of the range. 40 | * @param {Number} right Right side of the range. 41 | * @return {Number} Maximum sum of the elements of 42 | * subarray whithin the given range. 43 | */ 44 | function maxSubarrayPartitioner(array, left, right) { 45 | if (right - left <= 1) { 46 | return array[left]; 47 | } 48 | var middle = Math.floor((left + right) / 2); 49 | var leftSum = maxSubarrayPartitioner(array, left, middle); 50 | var rightSum = maxSubarrayPartitioner(array, middle, right); 51 | var crossSum = crossSubarray(array, left, middle, right); 52 | 53 | return Math.max(crossSum, leftSum, rightSum); 54 | } 55 | 56 | /** 57 | * Finds the maximum sum of the elements of a subarray in a given array 58 | * using the divide and conquer algorithm by Bentley, Jon (1984). 59 | * For example, for the sequence of values -2, 1, -3, 4, -1, 2, 1, -5, 4 60 | * the contiguous subarray with the largest sum is 4, -1, 2, 1, with sum 6. 61 | *

62 | * Time complexity: O(N log N). 63 | * 64 | * @example 65 | * var max = require('path-to-algorithms/src/searching/'+ 66 | * 'maximum-subarray-divide-and-conquer').maxSubarray; 67 | * console.log(max([-2, 1, -3, 4, -1, 2, 1, -5, 4])); // 6 68 | * 69 | * @public 70 | * @module searching/maximum-subarray-divide-and-conquer 71 | * @param {Array} array Input array. 72 | * @return {Number} Maximum sum of the elements of a subarray. 73 | */ 74 | function maxSubarray(array) { 75 | return maxSubarrayPartitioner(array, 0, array.length); 76 | } 77 | 78 | exports.maxSubarray = maxSubarray; 79 | 80 | })(typeof window === 'undefined' ? module.exports : window); 81 | -------------------------------------------------------------------------------- /src/searching/maximum-subarray.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Finds the maximum sum of the elements of a subarray in a given array 6 | * using the Kadane's algorithm. 7 | * For example, for the sequence of values -2, 1, -3, 4, -1, 2, 1, -5, 4 8 | * the contiguous subarray with the largest sum is 4, -1, 2, 1, with sum 6. 9 | *

10 | * Time complexity: O(N). 11 | * 12 | * @example 13 | * var max = require('path-to-algorithms/src/searching/'+ 14 | * 'maximum-subarray').maxSubarray; 15 | * console.log(max([-2, 1, -3, 4, -1, 2, 1, -5, 4])); // 6 16 | * 17 | * @public 18 | * @module searching/maximum-subarray 19 | * @param {Array} array Input array. 20 | * @return {Number} Maximum sum of the elements of a subarray. 21 | */ 22 | function maxSubarray(array) { 23 | var currentMax = array[0]; 24 | var max = array[0]; 25 | for (var i = 1; i < array.length; i += 1) { 26 | currentMax = Math.max(array[i], currentMax + array[i]); 27 | max = Math.max(max, currentMax); 28 | } 29 | return max; 30 | } 31 | 32 | exports.maxSubarray = maxSubarray; 33 | 34 | })(typeof window === 'undefined' ? module.exports : window); 35 | -------------------------------------------------------------------------------- /src/searching/quickselect.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Returns the n-th smallest element of list within 6 | * lo..hi inclusive (i.e. lo <= n <= hi).

7 | * Time complexity: O(N). 8 | * 9 | * @example 10 | * 11 | * var quickselect = require('path-to-algorithms/src/searching/'+ 12 | * 'quickselect').quickselect; 13 | * var result = quickselect([5, 1, 2, 2, 0, 3], 1, 0, 5); 14 | * console.log(result); // 1 15 | * 16 | * @public 17 | * @module searching/quickselect 18 | * @param {Array} arr Input array. 19 | * @param {Number} n A number of an element. 20 | * @param {Number} lo Low index. 21 | * @param {Number} hi High index. 22 | * @return Returns n-th smallest element. 23 | */ 24 | function quickselect(arr, n, lo, hi) { 25 | function partition(arr, lo, hi, pivotIdx) { 26 | function swap(arr, i, j) { 27 | var temp = arr[i]; 28 | arr[i] = arr[j]; 29 | arr[j] = temp; 30 | } 31 | var pivot = arr[pivotIdx]; 32 | swap(arr, pivotIdx, hi); 33 | for (var i = lo; i < hi; i += 1) { 34 | if (arr[i] < pivot) { 35 | swap(arr, i, lo); 36 | lo += 1; 37 | } 38 | } 39 | swap(arr, hi, lo); 40 | return lo; 41 | } 42 | 43 | if (arr.length <= n) { 44 | return undefined; 45 | } 46 | lo = lo || 0; 47 | hi = hi || arr.length - 1; 48 | if (lo === hi) { 49 | return arr[lo]; 50 | } 51 | while (hi >= lo) { 52 | var pivotIdx = 53 | partition(arr, lo, hi, lo + Math.floor(Math.random() * (hi - lo + 1))); 54 | if (n === pivotIdx) { 55 | return arr[pivotIdx]; 56 | } 57 | if (n < pivotIdx) { 58 | hi = pivotIdx - 1; 59 | } else { 60 | lo = pivotIdx + 1; 61 | } 62 | } 63 | return undefined; 64 | } 65 | exports.quickselect = quickselect; 66 | 67 | })(typeof window === 'undefined' ? module.exports : window); 68 | -------------------------------------------------------------------------------- /src/searching/recursive-binarysearch.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var binarySearch = (function () { 5 | /** 6 | * @private 7 | * @param {Array} array Array where we should find the index of the element 8 | * @param {Number} value Value of the element which index should be found 9 | * @param {Number} left Left index 10 | * @param {Number} right Right index 11 | * @returns {Number} index The index of the element or -1 if not found 12 | */ 13 | function recursiveBinarySearch(array, value, left, right) { 14 | if (left > right) { 15 | return -1; 16 | } 17 | var middle = Math.floor((right + left) / 2); 18 | if (array[middle] === value) { 19 | return middle; 20 | } else if (array[middle] > value) { 21 | return recursiveBinarySearch(array, value, left, middle - 1); 22 | } else { 23 | return recursiveBinarySearch(array, value, middle + 1, right); 24 | } 25 | } 26 | 27 | /** 28 | * Recursive version of binary search. 29 | * Searches for specific element in a given array using 30 | * the binary search algorithm.

31 | * Time complexity: O(log N). 32 | * 33 | * @example 34 | * 35 | * var search = require('path-to-algorithms/src/searching/'+ 36 | * 'recursive-binarysearch').binarySearch; 37 | * console.log(search([1, 2, 3, 4, 5], 4)); // 3 38 | * 39 | * @public 40 | * @module searching/recursive-binarysearch 41 | * @param {Array} array Input array. 42 | * @param {Number} value Value of the element which index should be found. 43 | * @returns {Number} Index of the element or -1 if not found. 44 | */ 45 | return function (array, value) { 46 | return recursiveBinarySearch(array, value, 0, array.length); 47 | }; 48 | 49 | }()); 50 | 51 | exports.binarySearch = binarySearch; 52 | 53 | })(typeof window === 'undefined' ? module.exports : window); 54 | -------------------------------------------------------------------------------- /src/sets/quickfind.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Keeps track of a set of elements partitioned into a 3 | * number of disjoint (nonoverlapping) subsets. 4 | * Allows to check whether the path between two nodes exists. 5 | * The algorithm is inspired by Robert Sedgewick's Java implementation. 6 | *
7 | * The algorithm is inspired by Robert Sedgewick's Java implementation. 8 | * {@link http://algs4.cs.princeton.edu/home/} 9 | * 10 | * @example 11 | * 12 | * var QuickFind = require('path-to-algorithms/src/sets/quickfind').QuickFind; 13 | * 14 | * var qfind = new QuickFind(10); 15 | * qfind.union(0, 1); 16 | * qfind.union(2, 1); 17 | * qfind.union(3, 4); 18 | * qfind.union(8, 9); 19 | * qfind.union(4, 8); 20 | * 21 | * console.log(qfind.connected(0, 9)); // false 22 | * console.log(qfind.connected(3, 9)); // true 23 | * 24 | * @public 25 | * @module sets/quickfind 26 | */ 27 | (function (exports) { 28 | 'use strict'; 29 | 30 | /** 31 | * Initialization.

32 | * Time complexity: O(N). 33 | * 34 | * @public 35 | * @constructor 36 | * @param {Numner} size Count of the nodes. 37 | */ 38 | exports.QuickFind = function (size) { 39 | this._ids = []; 40 | for (var i = 0; i < size; i += 1) { 41 | this._ids[i] = i; 42 | } 43 | }; 44 | 45 | /** 46 | * Connects two nodes - p and q.

47 | * Time complexity: O(N). 48 | * 49 | * @public 50 | * @method 51 | * @param {Number} p The first node. 52 | * @param {Number} q The second node. 53 | */ 54 | exports.QuickFind.prototype.union = function (p, q) { 55 | var size = this._ids.length; 56 | var pval = this._ids[p]; 57 | var qval = this._ids[q]; 58 | for (var i = 0; i < size; i += 1) { 59 | if (this._ids[i] === qval) { 60 | this._ids[i] = pval; 61 | } 62 | } 63 | }; 64 | 65 | /** 66 | * Checks whether two nodes are connected.

67 | * Time complexity: O(1). 68 | * 69 | * @public 70 | * @method 71 | * @param {Number} p The first node. 72 | * @param {Number} q The second node. 73 | * @return {Boolean} 74 | */ 75 | exports.QuickFind.prototype.connected = function (p, q) { 76 | return this._ids[p] === this._ids[q]; 77 | }; 78 | })(typeof window === 'undefined' ? module.exports : window); 79 | -------------------------------------------------------------------------------- /src/sets/quickunion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Keeps track of a set of elements partitioned into a 3 | * number of disjoint (nonoverlapping) subsets. 4 | * Allows to check whether the path between two nodes exists. 5 | *
6 | * The algorithm is inspired by Robert Sedgewick's Java implementation. 7 | * {@link http://algs4.cs.princeton.edu/home/} 8 | * 9 | * @example 10 | * 11 | * var QuickUnion = require('path-to-algorithms/' + 12 | * 'src/sets/quickunion').QuickUnion; 13 | * 14 | * var qunion = new QuickUnion(10); 15 | * qunion.union(0, 1); 16 | * qunion.union(2, 1); 17 | * qunion.union(3, 4); 18 | * qunion.union(8, 9); 19 | * qunion.union(4, 8); 20 | * 21 | * console.log(qunion.connected(0, 9)); // false 22 | * console.log(qunion.connected(3, 9)); // true 23 | * 24 | * @public 25 | * @module sets/quickunion 26 | */ 27 | 28 | (function (exports) { 29 | 'use strict'; 30 | 31 | /** 32 | * Initialization.

33 | * Time complexity: O(N). 34 | * 35 | * @public 36 | * @constructor 37 | * @param {Numner} size Count of the nodes. 38 | */ 39 | exports.QuickUnion = function (n) { 40 | this._ids = []; 41 | for (var i = 0; i < n; i += 1) { 42 | this._ids[i] = i; 43 | } 44 | }; 45 | 46 | /** 47 | * Finds the root of given node.

48 | * Time complexity: O(N). 49 | * @private 50 | * @param {Number} i The given node. 51 | * @return {Number} Root of the given node. 52 | */ 53 | exports.QuickUnion.prototype._root = function (i) { 54 | while (i !== this._ids[i]) { 55 | i = this._ids[i]; 56 | } 57 | return i; 58 | }; 59 | 60 | /** 61 | * Connects two nodes - p and q.

62 | * Time complexity: O(N). 63 | * 64 | * @public 65 | * @method 66 | * @param {Number} p The first node. 67 | * @param {Number} q The second node. 68 | */ 69 | exports.QuickUnion.prototype.union = function (p, q) { 70 | var pRoot = this._root(p); 71 | var qRoot = this._root(q); 72 | this._ids[pRoot] = qRoot; 73 | }; 74 | 75 | /** 76 | * Checks whether two nodes are connected.

77 | * Time complexity: O(N). 78 | * 79 | * @param {Number} p The first node. 80 | * @param {Number} q The second node. 81 | * @return {Boolean} True/false depending on whether the nodes are connected. 82 | */ 83 | exports.QuickUnion.prototype.connected = function (p, q) { 84 | return this._root(p) === this._root(q); 85 | }; 86 | })(typeof window === 'undefined' ? module.exports : window); 87 | -------------------------------------------------------------------------------- /src/sets/weightquickunion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Keeps track of a set of elements partitioned into a 3 | * number of disjoint (nonoverlapping) subsets. 4 | * Allows to check whether the path between two nodes exists. 5 | *
6 | * The algorithm is inspired by Robert Sedgewick's Java implementation. 7 | * {@link http://algs4.cs.princeton.edu/home/} 8 | * 9 | * @example 10 | * 11 | * var QuickUnion = require('path-to-algorithms/' + 12 | * 'src/sets/weightquickunion').QuickUnion; 13 | * 14 | * var qunion = new QuickUnion(10); 15 | * qunion.union(0, 1); 16 | * qunion.union(2, 1); 17 | * qunion.union(3, 4); 18 | * qunion.union(8, 9); 19 | * qunion.union(4, 8); 20 | * 21 | * console.log(qunion.connected(0, 9)); // false 22 | * console.log(qunion.connected(3, 9)); // true 23 | * 24 | * @public 25 | * @module sets/weightquickunion 26 | */ 27 | 28 | (function (exports) { 29 | 'use strict'; 30 | 31 | /** 32 | * Initialization.

33 | * Time complexity: O(N). 34 | * 35 | * @public 36 | * @constructor 37 | * @param {Numner} size Count of the nodes. 38 | */ 39 | exports.QuickUnion = function (n) { 40 | this._ids = []; 41 | this._size = []; 42 | for (var i = 0; i < n; i += 1) { 43 | this._ids[i] = i; 44 | this._size[i] = 1; 45 | } 46 | }; 47 | 48 | /** 49 | * Finds the root of given node.

50 | * Time complexity: O(log N). 51 | * @private 52 | * @param {Number} i The given node. 53 | * @return {Number} Root of the given node. 54 | */ 55 | exports.QuickUnion.prototype._root = function (i) { 56 | while (i !== this._ids[i]) { 57 | // this._ids[i] = this._ids[this._ids[i]]; //enables the path compression 58 | i = this._ids[i]; 59 | } 60 | return i; 61 | }; 62 | 63 | /** 64 | * Checks whether two nodes are connected.

65 | * Time complexity: O(log N). 66 | * 67 | * @param {Number} p The first node. 68 | * @param {Number} q The second node. 69 | * @return {Boolean} True/false depending on whether the nodes are connected. 70 | */ 71 | exports.QuickUnion.prototype.connected = function (p, q) { 72 | return this._root(p) === this._root(q); 73 | }; 74 | 75 | /** 76 | * Connects two nodes - p and q.

77 | * Time complexity: O(log N). 78 | * 79 | * @public 80 | * @method 81 | * @param {Number} p The first node. 82 | * @param {Number} q The second node. 83 | */ 84 | exports.QuickUnion.prototype.union = function (p, q) { 85 | var pf = this._root(p); 86 | var qf = this._root(q); 87 | if (pf === qf) { 88 | return; // already linked 89 | } 90 | var psz = this._size[qf]; 91 | var qsz = this._size[pf]; 92 | if (psz < qsz) { 93 | this._ids[pf] = qf; 94 | this._size[qf] += psz; 95 | } else { 96 | this._ids[qf] = pf; 97 | this._size[pf] += qsz; 98 | } 99 | }; 100 | 101 | })(typeof window === 'undefined' ? module.exports : window); 102 | -------------------------------------------------------------------------------- /src/shuffle/fisheryates.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * The shuffling algorithm of 7 | * Fisher-Yates.

8 | * Time complexity: O(N). 9 | * 10 | * @example 11 | * var shuffle = require('path-to-algorithms/src/' + 12 | * 'shuffle/fisheryates').shuffle; 13 | * console.log(shuffle([1, 2, 3, 4, 5])); // shuffled array 14 | * 15 | * @public 16 | * @module shuffle/fisheryates 17 | * @param {Array} array Array which should be shuffled. 18 | * @return {Array} Shuffled array. 19 | */ 20 | function shuffle(array) { 21 | var size = array.length; 22 | var rand; 23 | for (var i = 0; i < size; i += 1) { 24 | rand = Math.floor(i + Math.random() * (size - i)); 25 | [array[rand], array[i]] = [array[i], array[rand]]; 26 | } 27 | return array; 28 | } 29 | 30 | exports.shuffle = shuffle; 31 | 32 | })(typeof window === 'undefined' ? module.exports : window); 33 | -------------------------------------------------------------------------------- /src/shuffle/richarddurstenfeld.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * Shuffle of an array elements. 7 | * This algorithm is modified version of Fisher-Yates shuffle 8 | * algorithm and is introduced by Richard Durstenfeld.

9 | * Time complexity: O(N). 10 | * 11 | * @example 12 | * var shuffle = require('path-to-algorithms/src/shuffle' + 13 | * '/richarddurstenfeld').shuffle; 14 | * console.log(shuffle([1, 2, 3, 4, 5])); // random shuffled 15 | * 16 | * @public 17 | * @module shuffle/richarddurstenfeld 18 | * @param {Array} array An array which should be shuffled. 19 | * @return {Array} Shuffled array. 20 | */ 21 | function shuffle(array) { 22 | var arraySize = array.length - 1; 23 | var rand; 24 | var temp; 25 | for (var i = arraySize; i >= 0; i -= 1) { 26 | rand = Math.round(Math.random() * arraySize); 27 | temp = array[i]; 28 | array[i] = array[rand]; 29 | array[rand] = temp; 30 | } 31 | return array; 32 | } 33 | 34 | exports.shuffle = shuffle; 35 | 36 | }(typeof exports === 'undefined' ? window : exports)); 37 | -------------------------------------------------------------------------------- /src/sorting/3-way-string-quicksort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var quicksort = (function () { 5 | 6 | function charAt(str, i) { 7 | return (i < str.length) ? str.charCodeAt(i) : -1; 8 | } 9 | 10 | function swap(arr, i, j) { 11 | var temp = arr[j]; 12 | arr[j] = arr[i]; 13 | arr[i] = temp; 14 | } 15 | 16 | function quicksort(arr, lo, hi, d) { 17 | if (lo >= hi) { 18 | return; 19 | } 20 | var lowPointer = lo; 21 | var highPointer = hi; 22 | var p = charAt(arr[lo], d); 23 | var i = lo + 1; 24 | var current; 25 | 26 | while (i <= highPointer) { 27 | current = charAt(arr[i], d); 28 | if (current < p) { 29 | swap(arr, i, lowPointer); 30 | lowPointer += 1; 31 | } else if (current > p) { 32 | swap(arr, i, highPointer); 33 | highPointer -= 1; 34 | i += 1; 35 | } else { 36 | i += 1; 37 | } 38 | } 39 | 40 | quicksort(arr, lo, lowPointer - 1, d); 41 | if (p >= 0) { 42 | quicksort(arr, lowPointer, highPointer, d + 1); 43 | } 44 | quicksort(arr, highPointer + 1, hi, d); 45 | } 46 | 47 | /** 48 | * Effective inplace string sorting algorithm. 49 | * Algorithm is NOT stable. 50 | * 51 | * @example 52 | * 53 | * var sort = require('path-to-algorithms/src/sorting'+ 54 | * '/3-way-string-quicksort').quicksort; 55 | * console.log(sort(['bb', 'aa', 'cc'])); // [ 'aa', 'bb', 'cc' ] 56 | * 57 | * @public 58 | * @module sorting/3-way-string-quicksort 59 | * @param arr {Array} array which should be sorted. 60 | * @return {Array} Sorted array. 61 | */ 62 | return function sort(arr) { 63 | quicksort(arr, 0, arr.length - 1, 0); 64 | return arr; 65 | }; 66 | }()); 67 | 68 | exports.quicksort = quicksort; 69 | 70 | })(typeof window === 'undefined' ? module.exports : window); 71 | -------------------------------------------------------------------------------- /src/sorting/bubblesort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function comparator(a, b) { 5 | return a - b; 6 | } 7 | 8 | /** 9 | * Bubble sort algorithm.

10 | * Complexity: O(N^2). 11 | * 12 | * @example 13 | * var sort = require('path-to-algorithms/src/' + 14 | * 'sorting/bubblesort').bubbleSort; 15 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 16 | * 17 | * @public 18 | * @module sorting/bubblesort 19 | * @param {Array} array Input array. 20 | * @param {Function} cmp Optional. A function that defines an 21 | * alternative sort order. The function should return a negative, 22 | * zero, or positive value, depending on the arguments. 23 | * @return {Array} Sorted array. 24 | */ 25 | function bubbleSort(array, cmp) { 26 | cmp = cmp || comparator; 27 | var temp; 28 | for (var i = 0; i < array.length - 1 ; i += 1) { 29 | var swapCount = 0; 30 | for (var j = 0; j < array.length - 1 - i; j += 1) { 31 | if (cmp(array[j], array[j + 1 ]) > 0) { 32 | temp = array[j]; 33 | array[j] = array[j + 1]; 34 | array[j + 1] = temp; 35 | swapCount += 1; 36 | } 37 | } 38 | if (swapCount === 0){ 39 | break; 40 | } 41 | } 42 | return array; 43 | } 44 | 45 | exports.bubbleSort = bubbleSort; 46 | 47 | })(typeof window === 'undefined' ? module.exports : window); 48 | -------------------------------------------------------------------------------- /src/sorting/bucketsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | 'use strict'; 4 | 5 | var bucketSort = (function () { 6 | 7 | /** 8 | * Insertionsort. 9 | * 10 | * @private 11 | * @param {array} array Input array 12 | * @returns {array} array Sorted input array 13 | */ 14 | function insertionSort(array) { 15 | var current; 16 | var j; 17 | for (var i = 1; i < array.length; i += 1) { 18 | current = array[i]; 19 | j = i - 1; 20 | while (j >= 0 && current < array[j]) { 21 | array[j + 1] = array[j]; 22 | j -= 1; 23 | } 24 | array[j + 1] = current; 25 | } 26 | return array; 27 | } 28 | 29 | /** 30 | * Creates buckets for given array 31 | * 32 | * @private 33 | * @param {array} array Input array 34 | * @returns {array} buckets Array whith array for each bucket. 35 | * Each bucket contains an array with all elements 36 | * from the input which are with suitable size. 37 | */ 38 | function createBuckets(array) { 39 | var buckets = []; 40 | var currentBucket; 41 | var current; 42 | for (var i = 0; i < array.length; i += 1) { 43 | current = array[i]; 44 | currentBucket = Math.floor(current); 45 | buckets[currentBucket] = buckets[currentBucket] || []; 46 | buckets[currentBucket].push(current); 47 | } 48 | return buckets; 49 | } 50 | 51 | /** 52 | * Sorts the arrays from each bucket. 53 | * 54 | * @private 55 | * @param {array} buckets Given buckets 56 | * @returns {array} buckets Buckets with sorted arrays for each bucket 57 | */ 58 | function sortBuckets(buckets) { 59 | for (var i = 0; i < buckets.length; i += 1) { 60 | if (buckets[i] !== undefined) { 61 | insertionSort(buckets[i]); 62 | } 63 | } 64 | return buckets; 65 | } 66 | 67 | /** 68 | * Unions all buckets' arrays 69 | * 70 | * @private 71 | * @param {array} buckets Input buckets 72 | * @returns {array} result Sorted array which contains 73 | * all elements form each bucket 74 | */ 75 | function unionBuckets(buckets) { 76 | var result = []; 77 | var currentBucket; 78 | for (var i = 0; i < buckets.length; i += 1) { 79 | currentBucket = buckets[i]; 80 | if (currentBucket !== undefined) { 81 | result = result.concat(currentBucket); 82 | } 83 | } 84 | return result; 85 | } 86 | 87 | /** 88 | * Sorts given array with bucketsort.

89 | * Time complexity: O(N) in case the 90 | * data is with uniform distribution. 91 | * 92 | * @example 93 | * 94 | * var sort = require('path-to-algorithms/src/'+ 95 | * 'sorting/bucketsort').bucketSort; 96 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 97 | * 98 | * @public 99 | * @module sorting/bucketsort 100 | * @param {Array} array Input array which should be sorted. 101 | * @return {Array} Sorted array. 102 | */ 103 | return function (array) { 104 | var buckets = createBuckets(array); 105 | sortBuckets(buckets); 106 | return unionBuckets(buckets); 107 | }; 108 | }()); 109 | 110 | exports.bucketSort = bucketSort; 111 | 112 | })(typeof window === 'undefined' ? module.exports : window); 113 | -------------------------------------------------------------------------------- /src/sorting/countingsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var countingSort = (function () { 5 | 6 | /** 7 | * Gets the count of the elements into the input array. 8 | * 9 | * @private 10 | * @param {Array} array The input array. 11 | * @return {Array} The count of each element from the input array. 12 | */ 13 | function getCount(array) { 14 | var count = []; 15 | var current; 16 | for (var i = 0; i < array.length; i += 1) { 17 | current = array[i]; 18 | count[current] = (count[current] || 0) + 1; 19 | } 20 | return count; 21 | } 22 | 23 | /** 24 | * Gets the count of the elements which are less than a given. 25 | * 26 | * @private 27 | * @param {Array} array The input array. 28 | * @return {Array} less The count of the elements which. 29 | * are less than each element from the input. 30 | */ 31 | function getLessCount(array) { 32 | var less = []; 33 | var last; 34 | less[0] = array[0] || 0; 35 | for (var i = 1; i < array.length; i += 1) { 36 | last = array[i - 1] || 0; 37 | less[i] = last + less[i - 1]; 38 | } 39 | return less; 40 | } 41 | 42 | /** 43 | * Sorts the input array. 44 | * 45 | * @private 46 | * @param {Array} array Input which should be sorted. 47 | * @param {Array} less Count of the less elements for each element. 48 | * @return {Array} The sorted input. 49 | */ 50 | function sort(array, less) { 51 | var result = []; 52 | var currentPositions = []; 53 | var current; 54 | var position; 55 | for (var i = 0; i < array.length; i += 1) { 56 | current = array[i]; 57 | position = less[current]; 58 | if (currentPositions[current] === undefined) { 59 | currentPositions[current] = position; 60 | } 61 | result[currentPositions[current]] = current; 62 | currentPositions[current] += 1; 63 | } 64 | return result; 65 | } 66 | 67 | /** 68 | * Counting sort algorithm. It's correct only 69 | * for array of integers.

70 | * Time complexity: O(N). 71 | * 72 | * @example 73 | * var sort = require('path-to-algorithms/src/' + 74 | * 'sorting/countingsort').countingSort; 75 | * console.log(sort([2, 5, 1, 3, 4])); // [ 1, 2, 3, 4, 5 ] 76 | * 77 | * @public 78 | * @module sorting/countingsort 79 | * @param {Array} array Array which should be sorted. 80 | * @return {Array} Sorted array. 81 | */ 82 | return function (array) { 83 | var less = getLessCount(getCount(array)); 84 | return sort(array, less); 85 | }; 86 | }()); 87 | 88 | exports.countingSort = countingSort; 89 | 90 | })(typeof window === 'undefined' ? module.exports : window); 91 | -------------------------------------------------------------------------------- /src/sorting/heapsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function comparator(a, b) { 5 | return a - b; 6 | } 7 | 8 | var heapSort = (function () { 9 | 10 | /** 11 | * Finds the correct place of given element in given max heap. 12 | * 13 | * @private 14 | * @param {Array} array Array. 15 | * @param {Number} index Index of the element which palce in 16 | * the max heap should be found. 17 | * @param {Number} heapSize Size of the heap. 18 | * @param {function} cmp Comparison function. 19 | */ 20 | function heapify(array, index, heapSize, cmp) { 21 | var left = 2 * index + 1; 22 | var right = 2 * index + 2; 23 | var largest = index; 24 | 25 | if (left < heapSize && cmp(array[left], array[index]) > 0) { 26 | largest = left; 27 | } 28 | 29 | if (right < heapSize && cmp(array[right], array[largest]) > 0) { 30 | largest = right; 31 | } 32 | 33 | if (largest !== index) { 34 | var temp = array[index]; 35 | array[index] = array[largest]; 36 | array[largest] = temp; 37 | heapify(array, largest, heapSize, cmp); 38 | } 39 | } 40 | 41 | /** 42 | * Builds max heap from given array. 43 | * 44 | * @private 45 | * @param {Array} array Array which should be turned into max heap. 46 | * @param {function} cmp Comparison function. 47 | * @return {Array} array Array turned into max heap. 48 | */ 49 | function buildMaxHeap(array, cmp) { 50 | for (var i = Math.floor(array.length / 2); i >= 0; i -= 1) { 51 | heapify(array, i, array.length, cmp); 52 | } 53 | return array; 54 | } 55 | 56 | /** 57 | * Heapsort. Turns the input array into max 58 | * heap and after that sorts it.

59 | * Time complexity: O(N log N). 60 | * 61 | * @example 62 | * 63 | * var sort = require('path-to-algorithms/src' + 64 | * '/sorting/heapsort').heapSort; 65 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 66 | * 67 | * @public 68 | * @module sorting/heapsort 69 | * @param {Array} array Input array. 70 | * @param {Function} cmp Optional. A function that defines an 71 | * alternative sort order. The function should return a negative, 72 | * zero, or positive value, depending on the arguments. 73 | * @return {Array} Sorted array. 74 | */ 75 | return function (array, cmp) { 76 | cmp = cmp || comparator; 77 | var size = array.length; 78 | var temp; 79 | buildMaxHeap(array, cmp); 80 | for (var i = array.length - 1; i > 0; i -= 1) { 81 | temp = array[0]; 82 | array[0] = array[i]; 83 | array[i] = temp; 84 | size -= 1; 85 | heapify(array, 0, size, cmp); 86 | } 87 | return array; 88 | }; 89 | }()); 90 | 91 | exports.heapSort = heapSort; 92 | 93 | })(typeof window === 'undefined' ? module.exports : window); 94 | -------------------------------------------------------------------------------- /src/sorting/insertion-binary-sort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function comparator(a, b) { 5 | return a - b; 6 | } 7 | 8 | /** 9 | * Modified version of insertion sort. It uses binary search for finding 10 | * where the current element should be inserted. It's correct because 11 | * the binary search looks just in the first part of the array 12 | * which is actually sorted.

13 | * Time complexity: O(N^2). 14 | * 15 | * @example 16 | * 17 | * var sort = require('path-to-algorithms/src' + 18 | * '/sorting/insertion-binary-sort').insertionBinarySort; 19 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 20 | * 21 | * @public 22 | * @module sorting/insertion-binary-sort 23 | * @param {Array} array Input array. 24 | * @param {Function} cmp Optional. A function that defines an 25 | * alternative sort order. The function should return a negative, 26 | * zero, or positive value, depending on the arguments. 27 | * @return {Array} Sorted array. 28 | */ 29 | function insertionBinarySort(array, cmp) { 30 | cmp = cmp || comparator; 31 | var current; 32 | var middle; 33 | var left; 34 | var right; 35 | for (var i = 1; i < array.length; i += 1) { 36 | current = array[i]; 37 | left = 0; 38 | right = i; 39 | middle = Math.floor((left + right) / 2); 40 | while (left <= right) { 41 | if (cmp(array[middle], current) <= 0) { 42 | left = middle + 1; 43 | } else if (cmp(array[middle], current) > 0) { 44 | right = middle - 1; 45 | } 46 | middle = Math.floor((right + left) / 2); 47 | } 48 | for (var j = i; j > left; j -= 1) { 49 | array[j] = array[j - 1]; 50 | } 51 | array[j] = current; 52 | } 53 | return array; 54 | } 55 | 56 | exports.insertionBinarySort = insertionBinarySort; 57 | 58 | })(typeof window === 'undefined' ? module.exports : window); 59 | -------------------------------------------------------------------------------- /src/sorting/insertionsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function compare(a, b) { 5 | return a - b; 6 | } 7 | 8 | /** 9 | * Insertionsort algorithm.

10 | * Time complexity: O(N^2). 11 | * 12 | * @example 13 | * 14 | * var sort = require('path-to-algorithms/src' + 15 | * '/sorting/insertion-sort').insertionSort; 16 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 17 | * 18 | * @public 19 | * @module sorting/insertionsort 20 | * @param {Array} array Input array. 21 | * @param {Function} cmp Optional. A function that defines an 22 | * alternative sort order. The function should return a negative, 23 | * zero, or positive value, depending on the arguments. 24 | * @return {Array} Sorted array. 25 | */ 26 | function insertionSort(array, cmp) { 27 | cmp = cmp || compare; 28 | var current; 29 | var j; 30 | for (var i = 1; i < array.length; i += 1) { 31 | current = array[i]; 32 | j = i - 1; 33 | while (j >= 0 && cmp(array[j], current) > 0) { 34 | array[j + 1] = array[j]; 35 | j -= 1; 36 | } 37 | array[j + 1] = current; 38 | } 39 | return array; 40 | } 41 | 42 | exports.insertionSort = insertionSort; 43 | 44 | })(typeof window === 'undefined' ? module.exports : window); 45 | -------------------------------------------------------------------------------- /src/sorting/lsd.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Sorts strings lexicographically.

6 | * Time complexity: O(N*M) for N keys which have M or fewer digits. 7 | * 8 | * @example 9 | * 10 | * var sort = require('../src/sorting/lsd').lsd; 11 | * // [ 'aab', 'aaa', 'acc', 'bbb', 'bcc' ] 12 | * console.log(sort(['aab', 'bbb', 'aaa', 'acc', 'bcc'])); 13 | * 14 | * @public 15 | * @module sorting/lsd 16 | * @param {Array} arr Array which should be sorted. 17 | * @param {Number} letterIdx Optional. Index to start sorting from. 18 | * @return {Array} Sorted array. 19 | */ 20 | function lsd(arr, letterIdx) { 21 | var temp; 22 | var count; 23 | letterIdx = letterIdx || 1; 24 | for (var i = letterIdx - 1; i >= 0; i -= 1) { 25 | count = []; 26 | temp = []; 27 | for (var j = 0; j < arr.length; j += 1) { 28 | var charCode = arr[j].charCodeAt(i); 29 | var old = count[charCode + 1] || 0; 30 | count[charCode + 1] = old + 1; 31 | } 32 | for (var c = 0; c < count.length - 1; c += 1) { 33 | count[c] = count[c] || 0; 34 | count[c + 1] = count[c + 1] || 0; 35 | count[c + 1] += count[c]; 36 | } 37 | for (j = 0; j < arr.length; j += 1) { 38 | var code = arr[j].charCodeAt(i); 39 | temp[count[code]] = arr[j]; 40 | count[code] += 1; 41 | } 42 | for (j = 0; j < arr.length; j += 1) { 43 | arr[j] = temp[j]; 44 | } 45 | } 46 | return arr; 47 | } 48 | 49 | exports.lsd = lsd; 50 | 51 | })(typeof window === 'undefined' ? module.exports : window); 52 | -------------------------------------------------------------------------------- /src/sorting/mergesort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | /** 3 | * Mergesort module. 4 | */ 5 | 'use strict'; 6 | 7 | var ll = require('../data-structures/linked-list.js'); 8 | 9 | function compare(a, b) { 10 | return a - b; 11 | } 12 | 13 | /** 14 | * Mergesort method which is recursively called for sorting the input array. 15 | * 16 | * @public 17 | * @module sorting/mergesort 18 | * @param {Array} array The array which should be sorted. 19 | * @param {Function} cmp Compares two items in an array. 20 | * @param {Number} start Left side of the subarray. 21 | * @param {Number} end Right side of the subarray. 22 | * @returns {Array} Array with sorted subarray. 23 | * 24 | * @example 25 | * var array = [2, 4, 1, 5, 6, 7]; 26 | * var mergeSort = 27 | * require('path-to-algorithms/src/sorting/mergesort').mergeSort; 28 | * mergeSort(array); // [1, 2, 4, 5, 6, 7] 29 | */ 30 | function mergeSort(array, cmp, start, end) { 31 | cmp = cmp || compare; 32 | start = start || 0; 33 | end = end || array.length; 34 | if (Math.abs(end - start) <= 1) { 35 | return []; 36 | } 37 | var middle = Math.ceil((start + end) / 2); 38 | 39 | mergeSort(array, cmp, start, middle); 40 | mergeSort(array, cmp, middle, end); 41 | 42 | return mergeSort.merge(array, cmp, start, middle, end); 43 | } 44 | 45 | /** 46 | * Devides and sort merges two subarrays of given array 47 | * 48 | * @public 49 | * @module sorting/mergesort/merge 50 | * @param {Array} array The array which subarrays should be sorted. 51 | * @param {Number} start The start of the first subarray. 52 | * This subarray is with end middle - 1. 53 | * @param {Number} middle The start of the second array. 54 | * @param {Number} end end - 1 is the end of the second array. 55 | * @returns {Array} The array with sorted subarray. 56 | * 57 | * @example 58 | * var array = [1, 2, 3, 1, 4, 5, 6]; 59 | * var merge = 60 | * require('path-to-algorithms/src/sorting/mergesort').merge; 61 | * merge(array, function (a, b) { // [1, 1, 2, 3, 4, 5, 6] 62 | * return a - b; 63 | * }, 0, 4, 7); 64 | */ 65 | mergeSort.merge = function (array, cmp, start, middle, end) { 66 | var left = new ll.LinkedList(); 67 | var right = new ll.LinkedList(); 68 | 69 | var leftSize = middle - start; 70 | var rightSize = end - middle; 71 | var maxSize = Math.max(leftSize, rightSize); 72 | var size = end - start; 73 | var i; 74 | 75 | for (i = 0; i < maxSize; i += 1) { 76 | if (i < leftSize) { 77 | left.push(array[start + i]); 78 | } 79 | if (i < rightSize) { 80 | right.push(array[middle + i]); 81 | } 82 | } 83 | i = 0; 84 | while (i < size) { 85 | if (left.first && right.first) { 86 | if (cmp(left.first.data, right.first.data) > 0) { 87 | array[start + i] = right.shift().data; 88 | } else { 89 | array[start + i] = left.shift().data; 90 | } 91 | } else if (left.first) { 92 | array[start + i] = left.shift().data; 93 | } else { 94 | array[start + i] = right.shift().data; 95 | } 96 | i += 1; 97 | } 98 | return array; 99 | }; 100 | 101 | exports.mergeSort = mergeSort; 102 | 103 | }(typeof exports === 'undefined' ? window : exports)); 104 | -------------------------------------------------------------------------------- /src/sorting/msd.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function charCodeAt(str, i) { 5 | return (i < str.length) ? str.charCodeAt(i) : -1; 6 | } 7 | 8 | function sort(arr, lo, hi, d) { 9 | var temp = []; 10 | var count = []; 11 | var j; 12 | var idx; 13 | // Use Insertion sort when the 14 | // array is smaller than given threshold 15 | for (j = lo; j <= hi; j += 1) { 16 | idx = charCodeAt(arr[j], d) + 2; 17 | count[idx] = count[idx] || 0; 18 | count[idx] += 1; 19 | } 20 | for (j = 0; j < count.length - 1; j += 1) { 21 | count[j] = count[j] || 0; 22 | count[j + 1] = count[j + 1] || 0; 23 | count[j + 1] += count[j]; 24 | } 25 | for (j = lo; j <= hi; j += 1) { 26 | idx = charCodeAt(arr[j], d) + 1; 27 | temp[count[idx]] = arr[j]; 28 | count[idx] += 1; 29 | } 30 | for (j = lo; j <= hi; j += 1) { 31 | arr[j] = temp[j - lo]; 32 | } 33 | for (j = 0; j < count.length - 2; j += 1) { 34 | sort(arr, lo + count[j], lo + count[j + 1] - 1, d + 1); 35 | } 36 | } 37 | 38 | /** 39 | * Sorts given array lexicographically. 40 | * Algorithms knows how to treat 41 | * differently length strings.

42 | * Algorithm is stable. 43 | * Time complexity: O(N*M) for N keys which have M or fewer digits. 44 | * 45 | * @example 46 | * 47 | * var sort = require('../src/sorting/msd').msd; 48 | * // [ 'aab', 'aaa', 'acc', 'bbb', 'bcc' ] 49 | * console.log(sort(['aab', 'bbb', 'aaa', 'acc', 'bcc'])); 50 | * 51 | * @public 52 | * @module sorting/msd 53 | * @param {Array} arr Array which should be sorted. 54 | * @param {Number} d Optional. Digit from which sorting should start. 55 | * @return {Array} Sorted array. 56 | */ 57 | function msd(arr, d) { 58 | d = d || 0; 59 | sort(arr, 0, arr.length - 1, d); 60 | return arr; 61 | } 62 | 63 | exports.msd = msd; 64 | })(typeof window === 'undefined' ? module.exports : window); 65 | -------------------------------------------------------------------------------- /src/sorting/oddeven-sort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | /** 5 | * Odd even sort algorithm.

6 | * Complexity: O(N^2). 7 | * 8 | * @example 9 | * var sort = require('path-to-algorithms/src/' + 10 | * 'sorting/oddeven-sort').oddEvenSort; 11 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 12 | * 13 | * @public 14 | * @module sorting/oddeven-sort 15 | * @param {Array} array Input array. 16 | * @return {Array} Sorted array. 17 | */ 18 | function oddEvenSort(arr) { 19 | function swap(arr, i, j) { 20 | var temp = arr[i]; 21 | arr[i] = arr[j]; 22 | arr[j] = temp; 23 | } 24 | 25 | var sorted = false; 26 | while (!sorted) { 27 | sorted = true; 28 | for (var i = 1; i < arr.length - 1; i += 2) { 29 | if (arr[i] > arr[i + 1]) { 30 | swap(arr, i, i + 1); 31 | sorted = false; 32 | } 33 | } 34 | 35 | for (i = 0; i < arr.length - 1; i += 2) { 36 | if (arr[i] > arr[i + 1]) { 37 | swap(arr, i, i + 1); 38 | sorted = false; 39 | } 40 | } 41 | } 42 | return arr; 43 | } 44 | 45 | exports.oddEvenSort = oddEvenSort; 46 | 47 | })(typeof window === 'undefined' ? module.exports : window); 48 | -------------------------------------------------------------------------------- /src/sorting/quicksort-declarative.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | 'use strict'; 4 | 5 | function compare(a, b) { 6 | return a - b; 7 | } 8 | 9 | /** 10 | * Quicksort algorithm (declarative variant) 11 | * 12 | * @public 13 | * @param {array} array Array which should be sorted. 14 | * @return {array} Sorted array. 15 | */ 16 | var quickSort = (function () { 17 | 18 | /** 19 | * Recursively calls itself. 20 | * 21 | * @private 22 | * @param {array} array Array which should be processed 23 | */ 24 | function quicksort(array, cmp) { 25 | if (array.length < 1) { 26 | return array; 27 | } 28 | 29 | const [x, ...rest] = array; 30 | 31 | return [ 32 | ...quicksort(rest.filter(v => cmp(v, x) < 0), cmp), 33 | x, 34 | ...quicksort(rest.filter(v => cmp(v, x) >= 0), cmp) 35 | ]; 36 | } 37 | 38 | 39 | /** 40 | * Quicksort algorithm. In this version of quicksort used 41 | * declarative programming mechanisms.

42 | * Time complexity: O(N log(N)). 43 | * 44 | * @example 45 | * 46 | * var sort = require('path-to-algorithms/src' + 47 | * '/sorting/quicksort-declarative').quickSort; 48 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 49 | * 50 | * @public 51 | * @module sorting/quicksort-declarative 52 | * @param {Array} array Input array. 53 | * @param {Function} cmp Optional. A function that defines an 54 | * alternative sort order. The function should return a negative, 55 | * zero, or positive value, depending on the arguments. 56 | * @return {Array} Sorted array. 57 | */ 58 | return function (array, cmp) { 59 | cmp = cmp || compare; 60 | array = quicksort(array, cmp); 61 | return array; 62 | }; 63 | 64 | }()); 65 | 66 | exports.quickSort = quickSort; 67 | 68 | }(typeof exports === 'undefined' ? window : exports)); 69 | -------------------------------------------------------------------------------- /src/sorting/quicksort-middle.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | 'use strict'; 4 | 5 | function compare(a, b) { 6 | return a - b; 7 | } 8 | 9 | /** 10 | * Quicksort algorithm 11 | * 12 | * @public 13 | * @param {array} array Array which should be sorted. 14 | * @return {array} Sorted array. 15 | */ 16 | var quickSort = (function () { 17 | 18 | /** 19 | * Partitions the array in two parts by the middle elements. 20 | * All elements which are less than the chosen one goes left from it 21 | * all which are greater goes right from it. 22 | * Uses Hoare's partitioning algorithm. 23 | * 24 | * @param {array} array Array which should be partitioned 25 | * @param {number} left Left part of the array 26 | * @param {number} right Right part of the array 27 | * @return {number} 28 | */ 29 | function partition(array, left, right, cmp) { 30 | var pivot = array[Math.floor((left + right) / 2)]; 31 | var temp; 32 | while (left <= right) { 33 | while (cmp(array[left], pivot) < 0) { 34 | left += 1; 35 | } 36 | while (cmp(array[right], pivot) > 0) { 37 | right -= 1; 38 | } 39 | if (left <= right) { 40 | temp = array[left]; 41 | array[left] = array[right]; 42 | array[right] = temp; 43 | left += 1; 44 | right -= 1; 45 | } 46 | } 47 | return left; 48 | } 49 | 50 | /** 51 | * Recursively calls itself with different values for 52 | * left/right part of the array which should be processed 53 | * 54 | * @private 55 | * @param {array} array Array which should be processed 56 | * @param {number} left Left part of the array which should be processed 57 | * @param {number} right Right part of the array which should be processed 58 | */ 59 | function quicksort(array, left, right, cmp) { 60 | var mid = partition(array, left, right, cmp); 61 | if (left < mid - 1) { 62 | quicksort(array, left, mid - 1, cmp); 63 | } 64 | if (right > mid) { 65 | quicksort(array, mid, right, cmp); 66 | } 67 | } 68 | 69 | /** 70 | * Quicksort algorithm. In this version of quicksort used 71 | * middle element of array for the pivot.

72 | * Time complexity: O(N log(N)). 73 | * 74 | * @example 75 | * 76 | * var sort = require('path-to-algorithms/src' + 77 | * '/sorting/quicksort-middle').quickSort; 78 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 79 | * 80 | * @public 81 | * @module sorting/quicksort-middle 82 | * @param {Array} array Input array. 83 | * @param {Function} cmp Optional. A function that defines an 84 | * alternative sort order. The function should return a negative, 85 | * zero, or positive value, depending on the arguments. 86 | * @return {Array} Sorted array. 87 | */ 88 | return function (array, cmp) { 89 | cmp = cmp || compare; 90 | quicksort(array, 0, array.length - 1, cmp); 91 | return array; 92 | }; 93 | 94 | }()); 95 | 96 | exports.quickSort = quickSort; 97 | 98 | })(typeof window === 'undefined' ? module.exports : window); 99 | -------------------------------------------------------------------------------- /src/sorting/quicksort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 3 | 'use strict'; 4 | 5 | /** 6 | * The quicksort algorithm. It's complexity is O(nlog n). 7 | * 8 | * @public 9 | */ 10 | var quickSort = (function () { 11 | 12 | function compare(a, b) { 13 | return a - b; 14 | } 15 | 16 | /** 17 | * Swap the places of two elements 18 | * 19 | * @private 20 | * @param {array} array The array which contains the elements 21 | * @param {number} i The index of the first element 22 | * @param {number} j The index of the second element 23 | * @returns {array} array The array with swapped elements 24 | */ 25 | function swap(array, i, j) { 26 | var temp = array[i]; 27 | array[i] = array[j]; 28 | array[j] = temp; 29 | return array; 30 | } 31 | 32 | /** 33 | * Partitions given subarray using Lomuto's partitioning algorithm. 34 | * 35 | * @private 36 | * @param {array} array Input array 37 | * @param {number} left The start of the subarray 38 | * @param {number} right The end of the subarray 39 | */ 40 | function partition(array, left, right, compare) { 41 | var cmp = array[right - 1]; 42 | var minEnd = left; 43 | var maxEnd; 44 | for (maxEnd = left; maxEnd < right - 1; maxEnd += 1) { 45 | if (compare(array[maxEnd], cmp) < 0) { 46 | swap(array, maxEnd, minEnd); 47 | minEnd += 1; 48 | } 49 | } 50 | swap(array, minEnd, right - 1); 51 | return minEnd; 52 | } 53 | 54 | /** 55 | * Sorts given array. 56 | * 57 | * @private 58 | * @param {array} array Array which should be sorted 59 | * @param {number} left The start of the subarray which should be handled 60 | * @param {number} right The end of the subarray which should be handled 61 | * @returns {array} array Sorted array 62 | */ 63 | function quickSort(array, left, right, cmp) { 64 | if (left < right) { 65 | var p = partition(array, left, right, cmp); 66 | quickSort(array, left, p, cmp); 67 | quickSort(array, p + 1, right, cmp); 68 | } 69 | return array; 70 | } 71 | 72 | /** 73 | * Calls the quicksort function with it's initial values. 74 | * 75 | * @public 76 | * @param {array} array The input array which should be sorted 77 | * @returns {array} array Sorted array 78 | */ 79 | return function (array, cmp) { 80 | cmp = cmp || compare; 81 | return quickSort(array, 0, array.length, cmp); 82 | }; 83 | }()); 84 | 85 | exports.quickSort = quickSort; 86 | 87 | }(typeof exports === 'undefined' ? window : exports)); 88 | -------------------------------------------------------------------------------- /src/sorting/radixsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | var radixSort = (function () { 5 | 6 | /** 7 | * Returns the digit of a number that is 'lsdOffset' 8 | * places from the least significant digit. 9 | * 10 | * @private 11 | * @param {Number} number Number 12 | * @param {Number} lsdOffset Offset of the digit to return, counting 13 | * from the position of the least significant digit (e.g. lsdOffset = 0 14 | * will return the least significant digit itself) 15 | * @return {String} digit The specified number digit. Returns 'undefined' 16 | * if lsdOffset is bigger or equal to the number of digits of the 'number' 17 | * argument. 18 | */ 19 | var getDigit = function (number, lsdOffset) { 20 | var size = number.toString().length; 21 | var digit; 22 | 23 | if (lsdOffset >= 0 && lsdOffset < size) { 24 | digit = number.toString()[size - 1 - lsdOffset]; 25 | } 26 | 27 | return digit; 28 | }; 29 | 30 | /** 31 | * Least significant digit (LSD) Radix sort. A non-comparative, 32 | * stable integer sorting algorithm.

33 | * Worst-case time complexity is O(N K) for N keys with K being 34 | * the average key length, measured in number of digits. 35 | * 36 | * @example 37 | * var sort = require('path-to-algorithms/src/' + 38 | * 'sorting/radixsort').radixSort; 39 | * console.log(sort([2, 5, 1, 3, 4])); // [ 1, 2, 3, 4, 5 ] 40 | * 41 | * @public 42 | * @module sorting/radixsort 43 | * @param {Array} array Input integer array 44 | * @return {Array} Sorted array 45 | */ 46 | return function (array) { 47 | var size = array.length; 48 | var R = 10; /* Alphabet size ([0-9] for integers) */ 49 | var count; 50 | var digit; 51 | var i; 52 | var j; 53 | 54 | /* Find maximum key size */ 55 | var maxKeySize = (array[0] || '').toString().length; 56 | for (i = 1; i < size; i += 1) { 57 | var numStr = array[i].toString(); 58 | if (numStr.length > maxKeySize) { 59 | maxKeySize = numStr.length; 60 | } 61 | } 62 | 63 | for (i = 0; i < maxKeySize; i += 1) { 64 | /* Initialize count */ 65 | count = []; 66 | for (j = 0; j < R; j += 1) { 67 | count[j] = 0; 68 | } 69 | 70 | /* Count frequency of each array element */ 71 | for (j = 0; j < size; j += 1) { 72 | digit = getDigit(array[j], i) || 0; 73 | count[digit] += 1; 74 | } 75 | 76 | /* Compute cumulates */ 77 | for (j = 1; j < R; j += 1) { 78 | count[j] += count[j - 1]; 79 | } 80 | 81 | /* Move elements to auxiliary array */ 82 | var aux = []; 83 | for (j = size - 1; j >= 0; j -= 1) { 84 | digit = getDigit(array[j], i) || 0; 85 | count[digit] -= 1; 86 | aux[count[digit]] = array[j]; 87 | } 88 | 89 | /* Copy elements back from auxilary array */ 90 | for (j = 0; j < size; j += 1) { 91 | array[j] = aux[j]; 92 | } 93 | } 94 | return array; 95 | }; 96 | })(); 97 | 98 | exports.radixSort = radixSort; 99 | 100 | })(typeof window === 'undefined' ? module.exports : window); 101 | -------------------------------------------------------------------------------- /src/sorting/readme.md: -------------------------------------------------------------------------------- 1 | # Comparison of all sorting algorithms 2 | 3 | | Algorithm | Complexity | When to use? | 4 | |----------------------------|-----------------------------------------------------|--------------| 5 | | 3-way-string-quicksort.js | O(N^2) | | 6 | | bubblesort.js | O(N^2) | | 7 | | bucketsort.js | O(N) | | 8 | | countingsort.js | O(N) | | 9 | | heapsort.js | O(N log N) | | 10 | | insertion-binary-sort.js | O(N^2) | | 11 | | insertionsort.js | O(N^2) | | 12 | | lsd.js | O(N*M) for N keys which have M or fewer digits | | 13 | | mergesort.js | O(n log(n)) | | 14 | | msd.js | O(N*M) for N keys which have M or fewer digits | | 15 | | oddeven-sort.js | O(N^2) | | 16 | | quicksort-middle.js | O(N log(N)) | | 17 | | quicksort.js | O(nlog n) | | 18 | | radixsort.js | O(N K) for N keys with K being | | 19 | | recursive-insertionsort.js | O(N^2) | | 20 | | selectionsort.js | O(N^2) | | 21 | | shellsort.js | O((nlog(n))^2) | | 22 | -------------------------------------------------------------------------------- /src/sorting/recursive-insertionsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function compare(a, b) { 5 | return a - b; 6 | } 7 | 8 | /** 9 | * Recursive version of insertion sort.

10 | * Time complexity: O(N^2). 11 | * 12 | * @example 13 | * 14 | * var sort = require('path-to-algorithms/src/sorting/'+ 15 | * 'recursive-insertionsort').recursiveInsertionSort; 16 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 17 | * 18 | * @public 19 | * @module sorting/recursive-insertionsort 20 | * @param {Array} array Input array. 21 | * @param {Function} cmp Optional. A function that defines an 22 | * alternative sort order. The function should return a negative, 23 | * zero, or positive value, depending on the arguments. 24 | * @param {Number} max Optional. Index of the element which place 25 | * we should find in the current function call. 26 | * @return {Array} Sorted array. 27 | */ 28 | function recursiveInsertionSort(array, cmp, max) { 29 | cmp = cmp || compare; 30 | if (max === undefined) { 31 | max = array.length - 1; 32 | } 33 | if (max <= 0) { 34 | return array; 35 | } 36 | recursiveInsertionSort(array, cmp, max - 1); 37 | for (var i = max - 1, current = array[max]; 38 | i >= 0 && cmp(current, array[i]) < 0; i -= 1) { 39 | array[i + 1] = array[i]; 40 | } 41 | array[i + 1] = current; 42 | return array; 43 | } 44 | 45 | exports.recursiveInsertionSort = recursiveInsertionSort; 46 | 47 | })(typeof window === 'undefined' ? module.exports : window); 48 | -------------------------------------------------------------------------------- /src/sorting/selectionsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function compare(a, b) { 5 | return a - b; 6 | } 7 | 8 | /** 9 | * Selection sort.

10 | * Time complexity: O(N^2). 11 | * 12 | * @example 13 | * 14 | * var sort = require('path-to-algorithms/src/sorting/'+ 15 | * 'selectionsort').selectionSort; 16 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 17 | * 18 | * @public 19 | * @module sorting/selectionsort 20 | * @param {Array} array Input array. 21 | * @param {Function} cmp Optional. A function that defines an 22 | * alternative sort order. The function should return a negative, 23 | * zero, or positive value, depending on the arguments. 24 | * @return {Array} Sorted array. 25 | */ 26 | var selectionSort = function (array, cmp) { 27 | cmp = cmp || compare; 28 | var idx; 29 | var temp; 30 | for (var i = 0; i < array.length - 1; i += 1) { 31 | idx = i; 32 | for (var j = i + 1; j < array.length; j += 1) { 33 | if (cmp(array[idx], array[j]) > 0) { 34 | idx = j; 35 | } 36 | } 37 | temp = array[i]; 38 | array[i] = array[idx]; 39 | array[idx] = temp; 40 | } 41 | return array; 42 | }; 43 | 44 | exports.selectionSort = selectionSort; 45 | 46 | })(typeof window === 'undefined' ? module.exports : window); 47 | -------------------------------------------------------------------------------- /src/sorting/shellsort.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict'; 3 | 4 | function compare(a, b) { 5 | return a - b; 6 | } 7 | 8 | var shellSort = (function () { 9 | 10 | var gaps = [701, 301, 132, 57, 23, 10, 4, 1]; 11 | 12 | /** 13 | * Shellsort which uses the gaps 701, 301, 132, 57, 23, 10, 4, 1 and 14 | * insertion sort to sort sub-arrays which match for the different gaps. 15 | * 16 | * @example 17 | * 18 | * var sort = require('path-to-algorithms/src/' + 19 | * 'sorting/shellsort').shellSort; 20 | * console.log(sort([2, 5, 1, 0, 4])); // [ 0, 1, 2, 4, 5 ] 21 | * 22 | * @public 23 | * @module sorting/shellsort 24 | * @param {Array} array Input array. 25 | * @param {Function} cmp Optional. A function that defines an 26 | * alternative sort order. The function should return a negative, 27 | * zero, or positive value, depending on the arguments. 28 | * @return {Array} Sorted array. 29 | */ 30 | return function (array, cmp) { 31 | cmp = cmp || compare; 32 | 33 | var gap; 34 | var current; 35 | for (var k = 0; k < gaps.length; k += 1) { 36 | gap = gaps[k]; 37 | for (var i = gap; i < array.length; i += gap) { 38 | current = array[i]; 39 | for (var j = i; 40 | j >= gap && cmp(array[j - gap], current) > 0; j -= gap) { 41 | array[j] = array[j - gap]; 42 | } 43 | array[j] = current; 44 | } 45 | } 46 | return array; 47 | }; 48 | 49 | }()); 50 | 51 | exports.shellSort = shellSort; 52 | 53 | }(typeof exports === 'undefined' ? window : exports)); 54 | -------------------------------------------------------------------------------- /test/compression/burrows-wheeler/burrows-wheeler.spec.js: -------------------------------------------------------------------------------- 1 | var bw = require('../../../src/compression/burrows-wheeler/burrows-wheeler').burrowsWheeler; 2 | 3 | describe('Burrows Wheeler', function () { 4 | 'use strict'; 5 | 6 | it('should return "annnnb$aaaaa" for the entry "ananabanana"', function () { 7 | expect(bw.encode('ananabanana')).toEqual('annnnb$aaaaa'); 8 | }); 9 | 10 | it('should return "ananabanana" for the entry "annnnb$aaaaa"', function () { 11 | expect(bw.decode('annnnb$aaaaa')).toEqual('ananabanana'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/data-structures/binary-search-tree.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/data-structures/binary-search-tree.js'); 2 | var Node = mod.Node; 3 | var BinaryTree = mod.BinaryTree; 4 | 5 | describe('Node', function () { 6 | 'use strict'; 7 | 8 | it('should be a constructor function', function () { 9 | expect(typeof Node).toBe('function'); 10 | }); 11 | }); 12 | 13 | describe('Binary Tree', function () { 14 | 'use strict'; 15 | 16 | it('should be a constructor function', function () { 17 | expect(typeof BinaryTree).toBe('function'); 18 | }); 19 | it('should start with null root', function () { 20 | expect(new BinaryTree()._root).toBe(null); 21 | }); 22 | it('should insert and remove single node properly', function () { 23 | var bTree = new BinaryTree(); 24 | bTree.insert(15); 25 | var node = bTree.find(15); 26 | bTree.remove(node); 27 | expect(bTree._root).toBe(null); 28 | }); 29 | it('should remove root and replace with valid child', function () { 30 | var bTree = new BinaryTree(); 31 | bTree.insert(15); 32 | bTree.insert(30); 33 | bTree.insert(45); 34 | var node = bTree.find(15); 35 | bTree.remove(node); 36 | expect(bTree._root.value).toBe(30); 37 | }); 38 | it('should insert multiple nodes properly', function () { 39 | var bTree = new BinaryTree(); 40 | bTree.insert(10); 41 | bTree.insert(5); 42 | bTree.insert(15); 43 | bTree.insert(4); 44 | bTree.insert(6); 45 | bTree.insert(14); 46 | bTree.insert(16); 47 | var leftRootChild = bTree._root._left; 48 | var rightRootChild = bTree._root._right; 49 | expect(bTree._root.value).toBe(10); 50 | expect(leftRootChild.value).toBe(5); 51 | expect(rightRootChild.value).toBe(15); 52 | expect(leftRootChild._left.value).toBe(4); 53 | expect(leftRootChild._right.value).toBe(6); 54 | expect(rightRootChild._left.value).toBe(14); 55 | expect(rightRootChild._right.value).toBe(16); 56 | }); 57 | it('should remove multiple nodes properly', function () { 58 | var bTree = new BinaryTree(); 59 | bTree.insert(10); 60 | bTree.insert(5); 61 | bTree.insert(15); 62 | bTree.insert(4); 63 | bTree.insert(6); 64 | bTree.insert(7); 65 | bTree.insert(14); 66 | bTree.insert(16); 67 | var leftRootChild = bTree._root._left; 68 | var rightRootChild = bTree._root._right; 69 | var sixteen = bTree.find(16); 70 | bTree.remove(sixteen); 71 | expect(bTree._root.value).toBe(10); 72 | expect(leftRootChild.value).toBe(5); 73 | expect(rightRootChild.value).toBe(15); 74 | expect(leftRootChild._left.value).toBe(4); 75 | expect(leftRootChild._right.value).toBe(6); 76 | expect(leftRootChild._right._right.value).toBe(7); 77 | expect(rightRootChild._left.value).toBe(14); 78 | expect(rightRootChild._right).toBe(null); 79 | var fourteen = bTree.find(14); 80 | bTree.remove(fourteen); 81 | expect(rightRootChild._left).toBe(null); 82 | var five = bTree.find(5); 83 | bTree.remove(five); 84 | expect(leftRootChild.value).toBe(6); 85 | expect(leftRootChild._left.value).toBe(4); 86 | expect(leftRootChild._right.value).toBe(7); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /test/data-structures/bloomfilter.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/data-structures/bloomfilter.js'); 2 | var Bitmap = mod.Bitmap; 3 | var Bloomfilter = mod.Bloomfilter; 4 | 5 | describe('Bitmap', function() { 6 | 'use strict'; 7 | 8 | it('should be able to get and set values', function() { 9 | var bitmap = new Bitmap(1024); 10 | expect(bitmap.exists(0)).toBe(false); 11 | bitmap.set(0, true); 12 | expect(bitmap.exists(0)).toBe(true); 13 | expect(bitmap.exists(1023)).toBe(false); 14 | bitmap.set(1023, 1); 15 | expect(bitmap.exists(1023)).toBe(true); 16 | }); 17 | 18 | it('should be able to change everthing back', function() { 19 | var bitmap = new Bitmap(2048); 20 | for (var i = 0; i < 2048; i = i + 1) { 21 | expect(bitmap.get(i)).toBe(0); 22 | bitmap.set(i, 1); 23 | expect(bitmap.get(i)).toBe(1); 24 | bitmap.set(i, 0); 25 | expect(bitmap.get(i)).toBe(0); 26 | } 27 | }); 28 | }); 29 | 30 | describe('Bloomfilter', function() { 31 | 'use strict'; 32 | it('should be able to identify duplicates', function() { 33 | var bloomfilter = new Bloomfilter(1024, 0.01); 34 | expect(bloomfilter.get('a')).toBe(false); 35 | expect(bloomfilter.get('b')).toBe(false); 36 | bloomfilter.set('a'); 37 | expect(bloomfilter.get('a')).toBe(true); 38 | expect(bloomfilter.get('b')).toBe(false); 39 | bloomfilter.set('b'); 40 | expect(bloomfilter.get('a')).toBe(true); 41 | expect(bloomfilter.get('b')).toBe(true); 42 | }); 43 | 44 | it('should handle large amount of data inside', function() { 45 | var bloomfilter = new Bloomfilter(4096, 0.001); // high precision 46 | 47 | var falsePositive = 0; 48 | for (var i = 0; i < 1024; i = i + 1) { 49 | if (bloomfilter.get(i)) { 50 | falsePositive = falsePositive + 1; 51 | } 52 | bloomfilter.set(i, true); 53 | expect(bloomfilter.get(i)).toBe(true); 54 | } 55 | expect(falsePositive).toBeLessThan(100); // set a high theshold 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/data-structures/heap.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/data-structures/heap.js'); 2 | var Heap = mod.Heap; 3 | 4 | describe('Heap', function () { 5 | 'use strict'; 6 | 7 | it('should be a constructor function', function () { 8 | expect(typeof Heap).toBe('function'); 9 | }); 10 | it('should have default comparison function', function () { 11 | var heap = new Heap(); 12 | expect(typeof heap._cmp).toBe('function'); 13 | }); 14 | it('should add an object properly', function () { 15 | var heap = new Heap(); 16 | heap.add(1); 17 | expect(heap._heap[0]).toBe(1); 18 | }); 19 | it('should remove an object properly', function () { 20 | var heap = new Heap(); 21 | heap.add(1); 22 | var res = heap.extract(); 23 | expect(res).toBe(1); 24 | expect(heap._heap.length).toBe(0); 25 | }); 26 | it('should add multiple nodes properly', function () { 27 | var heap = new Heap(); 28 | heap.add(55); 29 | heap.add(11); 30 | heap.add(66); 31 | expect(heap._heap.indexOf(55)).toBeGreaterThan(-1); 32 | expect(heap._heap.indexOf(11)).toBeGreaterThan(-1); 33 | expect(heap._heap.indexOf(66)).toBeGreaterThan(-1); 34 | }); 35 | it('should remove multiple nodes properly (max heap)', function () { 36 | var heap = new Heap(); 37 | heap.add(55); 38 | heap.add(11); 39 | heap.add(66); 40 | var res = heap.extract(); 41 | expect(res).toBe(66); 42 | res = heap.extract(); 43 | expect(res).toBe(55); 44 | res = heap.extract(); 45 | expect(res).toBe(11); 46 | }); 47 | it('should remove multiple nodes properly (min heap)', function () { 48 | var heap = new Heap(function (a, b) { 49 | return b - a; 50 | }); 51 | heap.add(55); 52 | heap.add(11); 53 | heap.add(66); 54 | var res = heap.extract(); 55 | expect(res).toBe(11); 56 | res = heap.extract(); 57 | expect(res).toBe(55); 58 | res = heap.extract(); 59 | expect(res).toBe(66); 60 | }); 61 | it('should update top node properly', function () { 62 | var heap = new Heap(function (a, b) { 63 | return a.val - b.val; 64 | }); 65 | var objectToUpdate = { val: 66 }; 66 | heap.add(objectToUpdate); 67 | heap.add({ val: 11 }); 68 | heap.add({ val: 55 }); 69 | objectToUpdate.val = 0; 70 | heap.update(objectToUpdate); 71 | var res = heap.extract(); 72 | expect(res.val).toBe(55); 73 | res = heap.extract(); 74 | expect(res.val).toBe(11); 75 | res = heap.extract(); 76 | expect(res.val).toBe(0); 77 | }); 78 | it('should update bottom node properly', function () { 79 | var heap = new Heap(function (a, b) { 80 | return a.val - b.val; 81 | }); 82 | var objectToUpdate = { val: 0 }; 83 | heap.add(objectToUpdate); 84 | heap.add({ val: 11 }); 85 | heap.add({ val: 55 }); 86 | objectToUpdate.val = 66; 87 | heap.update(objectToUpdate); 88 | var res = heap.extract(); 89 | expect(res.val).toBe(66); 90 | res = heap.extract(); 91 | expect(res.val).toBe(55); 92 | res = heap.extract(); 93 | expect(res.val).toBe(11); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/data-structures/interval-tree.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/data-structures/interval-tree.js'); 2 | var IntervalTree = mod.IntervalTree; 3 | 4 | describe('IntervalTree', function () { 5 | 'use strict'; 6 | 7 | it('should correctly detect intersections', function () { 8 | var it = new IntervalTree(); 9 | 10 | it.add([10383734, 10594186]) 11 | it.add([10383734, 10594186]) 12 | it.add([8891125, 9095610]) 13 | it.add([9495571, 9677853]) 14 | it.add([10093457, 10257167]) 15 | it.add([9303743, 9404967]) 16 | it.intersects([9303743, 9303744]) 17 | expect(it.intersects([9303743, 9303744])).toBe(true) 18 | expect(it.intersects([10383734, 10383734])).toBe(true); 19 | 20 | it.add([9495571, 9677853]) 21 | it.add([9303743, 9404967]) 22 | 23 | expect(it.intersects([9303743, 9303744])).toBe(true) 24 | expect(it.intersects([9303742, 9303742])).toBe(false) 25 | 26 | expect(it.intersects([9404967,9404967])).toBe(true) 27 | expect(it.intersects([9404968,9404969])).toBe(false) 28 | 29 | it = new IntervalTree(); 30 | 31 | expect(it.intersects([1,2])).toBe(false); 32 | 33 | it.add([1,2]); 34 | expect(it.contains(0.4)).toBe(false); 35 | expect(it.contains(1.4)).toBe(true); 36 | 37 | expect(it.intersects([0,3])).toBe(true); 38 | expect(it.intersects([1.5,1.6])).toBe(true); 39 | expect(it.intersects([2.1,3.0])).toBe(false); 40 | 41 | it.add([1.4,2.1]); 42 | 43 | expect(it.intersects([0,3])).toBe(true); 44 | expect(it.intersects([1.5,1.6])).toBe(true); 45 | 46 | expect(it.intersects([2.1,3.0])).toBe(true); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/data-structures/red-black-tree.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/data-structures/red-black-tree.js'); 2 | var Vertex = mod.Node; 3 | var RBTree = mod.RBTree; 4 | var Colors = mod.Colors; 5 | 6 | describe('Node', function () { 7 | 'use strict'; 8 | 9 | it('should be a constructor function', function () { 10 | expect(typeof Vertex).toBe('function'); 11 | }); 12 | 13 | it('should set all properties via the constructor', function () { 14 | var node = new Vertex('key', 'value', 1, 2, Colors.RED); 15 | expect(node.getKey()).toBe('key'); 16 | expect(node.getLeft()).toBe(1); 17 | expect(node.getRight()).toBe(2); 18 | expect(node.getValue()).toBe('value'); 19 | expect(node.isRed()).toBeTruthy(); 20 | }); 21 | 22 | describe('Node flipColor', function () { 23 | it('should has method flipColor', function () { 24 | var node = new Vertex(); 25 | expect(typeof node.flipColor).toBe('function'); 26 | }); 27 | it('should work properly', function () { 28 | var node = new Vertex(); 29 | expect(node.isRed()).toBe(false); 30 | node.flipColor(); 31 | expect(node.isRed()).toBe(true); 32 | node.flipColor(); 33 | expect(node.isRed()).toBe(false); 34 | }); 35 | }); 36 | }); 37 | 38 | describe('RBTree', function () { 39 | 'use strict'; 40 | 41 | it('should be a constructor function', function () { 42 | expect(typeof RBTree).toBe('function'); 43 | }); 44 | it('should initialize root to null by default', function () { 45 | expect(new RBTree()._root).toBeNull(); 46 | }); 47 | 48 | describe('node insertion', function () { 49 | it('should be able to insert a node in empty tree', function () { 50 | var tree = new RBTree(); 51 | tree.put('foo', 'bar'); 52 | expect(tree._root.getKey()).toBe('foo'); 53 | expect(tree._root.getValue()).toBe('bar'); 54 | }); 55 | 56 | it('should be able to insert a node in 1 level tree', function () { 57 | var tree = new RBTree(); 58 | tree.put(1, 'bar'); 59 | tree.put(0, 'baz'); 60 | expect(tree._root.getLeft()).not.toBeNull(); 61 | expect(tree._root.getLeft().isRed()).toBeTruthy(); 62 | tree.put(2, 'baz'); 63 | expect(tree._root.getRight()).not.toBeNull(); 64 | expect(tree._root.getRight().isRed()).toBeFalsy(); 65 | 66 | tree = new RBTree(); 67 | tree.put(1, 'bar'); 68 | tree.put(2, 'foo'); 69 | tree.put(3, 'baz'); 70 | expect(tree._root.getRight()).not.toBeNull(); 71 | expect(tree._root.getLeft()).not.toBeNull(); 72 | expect(tree._root.isRed()).toBeFalsy(); 73 | expect(tree._root.getRight().isRed()).toBeFalsy(); 74 | expect(tree._root.getLeft().isRed()).toBeFalsy(); 75 | tree.put(4, 'foobar'); 76 | tree.put(5, 'foobar'); 77 | expect(tree._root.getRight().getRight()).not.toBeNull(); 78 | expect(tree._root.getRight().getRight().isRed()).toBeFalsy(); 79 | }); 80 | 81 | }); 82 | 83 | describe('get method', function () { 84 | it('should be able to find value by given key', function () { 85 | var tree = new RBTree(); 86 | expect(tree.get(1)).toBeUndefined(); 87 | tree.put(1, 'baz'); 88 | expect(tree.get(1)).toBe('baz'); 89 | tree.put(2, 'foo'); 90 | expect(tree.get(2)).toBe('foo'); 91 | tree.put(3, 'bar'); 92 | expect(tree.get(3)).toBe('bar'); 93 | expect(tree.get(4)).toBeUndefined(); 94 | tree.put(5, 'foobar'); 95 | expect(tree.get(5)).toBe('foobar'); 96 | tree.put(5, 'foobar1'); 97 | expect(tree.get(5)).toBe('foobar1'); 98 | }); 99 | }); 100 | 101 | describe('levelOrderTraversal method', function () { 102 | it('should be able to traverse tree in level order', function () { 103 | var tree = new RBTree(); 104 | expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: Tree is empty'); 105 | tree.put(10); 106 | tree.put(20); 107 | expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10'); 108 | tree.put(30); 109 | expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10 30'); 110 | tree.put(45); 111 | expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10 45 30'); 112 | tree.put(5); 113 | expect(tree.levelOrderTraversal()).toBe('Level Order Traversal -: 20 10 45 5 30'); 114 | }); 115 | }); 116 | 117 | }); 118 | -------------------------------------------------------------------------------- /test/data-structures/segment-tree.spec.js: -------------------------------------------------------------------------------- 1 | var SegmentTree = require('../../src/data-structures/segment-tree.js') 2 | .SegmentTree; 3 | 4 | var defaultAggregate = function (a, b) { 5 | 'use strict'; 6 | return Math.min(a, b); 7 | }; 8 | 9 | describe('Segment Tree', function () { 10 | 'use strict'; 11 | 12 | describe('indexing', function () { 13 | 14 | it('should be a constructor function', function () { 15 | expect(typeof SegmentTree).toBe('function'); 16 | }); 17 | 18 | it('should start with null original array', function () { 19 | expect(new SegmentTree()._original).toBe(null); 20 | }); 21 | 22 | it('should start with empty array as data', function () { 23 | expect(new SegmentTree()._data).not.toBe(null); 24 | expect(new SegmentTree()._data.length).toBe(0); 25 | }); 26 | 27 | it('should work with empty arrays', function () { 28 | var tree = SegmentTree.indexArray([], Infinity, defaultAggregate); 29 | expect(tree._data).toBeTruthy(); 30 | expect(tree._data.length).toBe(0); 31 | }); 32 | 33 | it('should index arrays with one element', function () { 34 | var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate); 35 | expect(tree._data).toBeTruthy(); 36 | expect(tree._data.length).toBe(1); 37 | }); 38 | 39 | it('should index any array', function () { 40 | var tree = SegmentTree.indexArray([1, 2, 3], Infinity, defaultAggregate); 41 | expect(tree._data).toEqual([1, 1, 3, 1, 2]); 42 | 43 | tree = SegmentTree.indexArray([1, 2, 3, 6], Infinity, defaultAggregate); 44 | expect(tree._data).toEqual([1, 1, 3, 1, 2, 3, 6]); 45 | }); 46 | 47 | }); 48 | 49 | describe('should find the proper value at given interval', function () { 50 | 51 | it('should properly find the minimum when in range', function () { 52 | var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate); 53 | expect(tree.query(0, 0)).toBe(1); 54 | 55 | tree = SegmentTree.indexArray([1, 2], Infinity, defaultAggregate); 56 | expect(tree.query(0, 0)).toBe(1); 57 | expect(tree.query(0, 1)).toBe(1); 58 | expect(tree.query(1, 1)).toBe(2); 59 | 60 | tree = SegmentTree.indexArray([1, -1, 2], Infinity, defaultAggregate); 61 | expect(tree.query(0, 2)).toBe(-1); 62 | expect(tree.query(0, 1)).toBe(-1); 63 | expect(tree.query(1, 1)).toBe(-1); 64 | expect(tree.query(1, 2)).toBe(-1); 65 | expect(tree.query(2, 2)).toBe(2); 66 | }); 67 | 68 | it('should properly find the minimum when outside range', function () { 69 | var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate); 70 | expect(tree.query(0, 2)).toBe(1); 71 | 72 | tree = SegmentTree.indexArray([1, 2, 3], Infinity, defaultAggregate); 73 | expect(tree.query(0, 20)).toBe(1); 74 | expect(tree.query(2, 20)).toBe(3); 75 | expect(Number.isFinite(tree.query(20, 25))).toBe(false); 76 | }); 77 | 78 | it('should throw when the start index is bigger than end', function () { 79 | var tree = SegmentTree.indexArray([1], Infinity, defaultAggregate); 80 | expect(function () { 81 | tree.query(2, 1); 82 | }).toThrow(); 83 | expect(function () { 84 | tree.query(1, 1); 85 | }).not.toThrow(); 86 | }); 87 | }); 88 | }); 89 | 90 | -------------------------------------------------------------------------------- /test/data-structures/splay-tree.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/data-structures/splay-tree.js'); 2 | var Node = mod.Node; 3 | var SplayTree = mod.SplayTree; 4 | 5 | describe('Node', function () { 6 | 'use strict'; 7 | 8 | it('should be a constructor function', function () { 9 | expect(typeof Node).toBe('function'); 10 | }); 11 | it('should be a construct properly', function () { 12 | var node = new Node(10, null, null, null); 13 | expect(node.value).toBe(10); 14 | expect(node._left).toBe(null); 15 | expect(node._right).toBe(null); 16 | expect(node._parent).toBe(null); 17 | }); 18 | it('should reference children/parent properly', function () { 19 | var root = new Node(10, null, null, null); 20 | var left = new Node(5, null, null, root); 21 | var right = new Node(15, null, null, root); 22 | root._left = left; 23 | root._right = right; 24 | expect(root.value).toBe(10); 25 | expect(root._left).toBe(left); 26 | expect(root._right).toBe(right); 27 | expect(root._parent).toBe(null); 28 | }); 29 | }); 30 | 31 | describe('SplayTree', function () { 32 | 'use strict'; 33 | 34 | it('should be a constructor function', function () { 35 | expect(typeof SplayTree).toBe('function'); 36 | }); 37 | it('should start with null root', function () { 38 | expect(new SplayTree()._root).toBe(null); 39 | }); 40 | it('should insert and remove correctly', function () { 41 | var sTree = new SplayTree(); 42 | sTree.insert(10); 43 | sTree.remove(10); 44 | expect(sTree._root).toBe(null); 45 | }); 46 | it('should splay correctly upon inserts', function () { 47 | var sTree = new SplayTree(); 48 | sTree.insert(10); 49 | sTree.insert(5); 50 | sTree.insert(15); 51 | sTree.insert(7); 52 | sTree.insert(12); 53 | expect(sTree._root.value).toBe(12); 54 | expect(sTree._root._left.value).toBe(7); 55 | expect(sTree._root._right.value).toBe(15); 56 | }); 57 | it('should splay correctly upon search', function () { 58 | var sTree = new SplayTree(); 59 | sTree.insert(10); 60 | sTree.insert(5); 61 | sTree.insert(15); 62 | sTree.insert(7); 63 | sTree.insert(12); 64 | sTree.search(5); 65 | expect(sTree._root.value).toBe(5); 66 | expect(sTree._root._right.value).toBe(7); 67 | expect(sTree._root._right._right.value).toBe(12); 68 | }); 69 | it('should splay correctly upon remove', function () { 70 | var sTree = new SplayTree(); 71 | sTree.insert(10); 72 | sTree.insert(5); 73 | sTree.insert(15); 74 | sTree.insert(7); 75 | sTree.insert(12); 76 | sTree.remove(10); 77 | expect(sTree._root.value).toBe(7); 78 | expect(sTree._root._left.value).toBe(5); 79 | expect(sTree._root._right.value).toBe(12); 80 | expect(sTree._root._right._right.value).toBe(15); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/graphics/bezier.spec.js: -------------------------------------------------------------------------------- 1 | var bezier = require('../../src/graphics/bezier'); 2 | var linearBezier = bezier.linearBezier; 3 | var quadraticBezier = bezier.quadraticBezier; 4 | var cubicBezier = bezier.cubicBezier; 5 | 6 | // see https://www.geogebra.org/m/ek7RHvuc for graphical representation of test values 7 | 8 | describe('linearBezier', function () { 9 | 'use strict'; 10 | 11 | it('should return 0.5 for p0=0 p1=1 t=0.5', function () { 12 | expect(linearBezier(0, 1, 0.5)).toEqual(0.5); 13 | }); 14 | 15 | it('should return -2.8 for p0=-4.67 p1=-0.7 t=0.47', function () { 16 | expect(linearBezier(-4.67, -0.7, 0.47)).toBeCloseTo(-2.8, 1); 17 | }); 18 | 19 | it('should return 2.67 for p0=-0.6 p1=6.33 t=0.47', function () { 20 | expect(linearBezier(-0.6, 6.33, 0.47)).toBeCloseTo(2.67, 1); 21 | }); 22 | }); 23 | 24 | describe('quadraticBezier', function () { 25 | 'use strict'; 26 | 27 | it('should return 1 for p0=0 p1=1 p2=2 t=0.5', function () { 28 | expect(quadraticBezier(0, 1, 2, 0.5)).toEqual(1); 29 | }); 30 | 31 | it('should return 7.15 for p0=2.33 p1=8.23 p2=10.77 t=0.47', function () { 32 | expect(quadraticBezier(2.33, 8.23, 10.77, 0.47)).toBeCloseTo(7.15, 1); 33 | }); 34 | 35 | it('should return 6.84 for p0=4.67 p1=8.93 p2=4.9 t=0.47', function () { 36 | expect(quadraticBezier(4.67, 8.93, 4.9, 0.47)).toBeCloseTo(6.84, 1); 37 | }); 38 | }); 39 | 40 | describe('cubicBezier', function () { 41 | 'use strict'; 42 | 43 | it('should return 1.5 for p0=0 p1=1 p2=2 p3=3 t=0.5', function () { 44 | expect(cubicBezier(0, 1, 2, 3, 0.5)).toEqual(1.5); 45 | }); 46 | 47 | it('should return 9.78 for p0=2.4 p1=1.33 p2=19.87 p3=18.13 t=0.47', function () { 48 | expect(cubicBezier(2.4, 1.33, 19.87, 18.13, 0.47)).toBeCloseTo(9.78, 1); 49 | }); 50 | 51 | it('should return -4.87 for p0=-7.03 p1=-1.4 p2=-10.63 p3=4.5 t=0.47', function () { 52 | expect(cubicBezier(-7.03, -1.4, -10.63, 4.5, 0.47)).toBeCloseTo(-4.87, 1); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/graphics/grapham.spec.js: -------------------------------------------------------------------------------- 1 | var convexHull = require('../../src/graphics/graham').convexHull; 2 | 3 | const points = [ 4 | { x: 0, y: 0 }, 5 | { x: 1, y: 0 }, 6 | { x: 0, y: 1 }, 7 | { x: 0.15, y: 0.15 }, 8 | { x: 0.5, y: 0.5 } 9 | ]; 10 | 11 | describe('Graham\'s algorithm for convex hull', function() { 12 | 'use strict'; 13 | 14 | it('should not throw with empty list', () => { 15 | expect(() => convexHull([])).not.toThrow(); 16 | }); 17 | 18 | it('should calculate the convex hull', () => { 19 | expect(convexHull(points)).toEqual([ 20 | { x: 0, y: 0 }, 21 | { x: 1, y: 0 }, 22 | { x: 0.5, y: 0.5 }, 23 | { x: 0, y: 1 } 24 | ]); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/graphs/others/tarjan-connected-components.spec.js: -------------------------------------------------------------------------------- 1 | var tj = require('../../../src/graphs/others/tarjan-connected-components').tarjanConnectedComponents; 2 | 3 | var nonConnected = { 4 | v1: [], 5 | v2: [], 6 | v3: [], 7 | v4: [], 8 | v5: [] 9 | }; 10 | 11 | var cyclicGraph = { 12 | v1: ['v2'], 13 | v2: ['v3'], 14 | v3: ['v4'], 15 | v4: ['v5'], 16 | v5: ['v1'] 17 | }; 18 | 19 | describe('Tarjan\'s algorithm for finding connected components', function () { 20 | 'use strict'; 21 | it('should be defined', function () { 22 | expect(typeof tj).toBe('function'); 23 | }); 24 | 25 | it('should return an array', function () { 26 | expect(tj() instanceof Array).toBeTruthy(); 27 | }); 28 | 29 | it('should work with non-connected graphs', function () { 30 | expect(tj(nonConnected)).toEqual([['v1'], ['v2'], ['v3'], ['v4'], ['v5']]); 31 | }); 32 | 33 | it('should workw ith cycles', function () { 34 | expect(tj(cyclicGraph)).toEqual([['v5', 'v4', 'v3', 'v2', 'v1']]); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/graphs/others/topological-sort.spec.js: -------------------------------------------------------------------------------- 1 | var ts = require('../../../src/graphs/others/topological-sort').topologicalSort; 2 | 3 | describe('Topological sort', function () { 4 | 'use strict'; 5 | it('should be defined', function () { 6 | expect(typeof ts).toBe('function'); 7 | }); 8 | 9 | it('should work with empty graphs', function () { 10 | expect(ts({})).toEqual([]); 11 | }); 12 | 13 | it('should give the proper topological order', function () { 14 | expect(ts({ v1: [] })).toEqual(['v1']); 15 | var graph = { 16 | v1: ['v2'], 17 | v2: ['v3'], 18 | v3: [] 19 | }; 20 | expect(ts(graph)).toEqual(['v1', 'v2', 'v3']); 21 | graph = { 22 | v1: ['v2', 'v5'], 23 | v2: [], 24 | v3: ['v1', 'v2', 'v4', 'v5'], 25 | v4: [], 26 | v5: [] 27 | }; 28 | expect(ts(graph)).toEqual(['v3', 'v4', 'v1', 'v5', 'v2']); 29 | }); 30 | 31 | it('should throw an error on cycle', function () { 32 | function runTs() { 33 | ts({ 34 | v1: ['v2'], 35 | v2: ['v1'] 36 | }); 37 | } 38 | expect(runTs).toThrow(); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/graphs/searching/bfs.spec.js: -------------------------------------------------------------------------------- 1 | /* jshint multistr: true */ 2 | 3 | var graph = [[0, 0, 0, 0, 1], 4 | [0, 0, 0, 1, 0], 5 | [0, 0, 0, 0, 0], 6 | [1, 0, 1, 0, 0], 7 | [0, 1, 0, 1, 0]]; 8 | 9 | var bfs = require('../../../src/graphs/searching/bfs').bfs; 10 | 11 | describe('BFS', function () { 12 | 'use strict'; 13 | 14 | it('should work with empty graph', function () { 15 | expect(bfs([], 0, 0)).toEqual([0]); 16 | }); 17 | 18 | it('should return the correct output when used with\ 19 | source node equals target node', function () { 20 | expect(bfs(graph, 2, 2)).toEqual([2]); 21 | }); 22 | 23 | it('should return work with cycles', function () { 24 | expect(bfs(graph, 0, 2)).toEqual([0, 4, 3, 2]); 25 | }); 26 | 27 | it('should return falsy value when there\'s no path', function () { 28 | var graph = [[0, 0, 0, 0, 1], 29 | [0, 0, 0, 1, 0], 30 | [0, 0, 0, 0, 0], 31 | [1, 0, 0, 0, 0], 32 | [0, 1, 0, 1, 0]]; 33 | expect(bfs(graph, 0, 2)).toBeFalsy(); 34 | }); 35 | 36 | /** 37 | * In this case the graph should not 38 | * update the parent of 2, in case it was called 39 | * with source 0 and target 2, after the first iteration. 40 | * 41 | * 0 ---> 1 42 | * \ | 43 | * \ v 44 | * -> 2 45 | */ 46 | it('should not update the parent node once set', function () { 47 | var graph = [[0, 1, 1], 48 | [0, 0, 1], 49 | [0, 0, 0]]; 50 | expect(bfs(graph, 0, 2)).toEqual([0, 2]); 51 | }); 52 | 53 | }); 54 | -------------------------------------------------------------------------------- /test/graphs/searching/dfs.spec.js: -------------------------------------------------------------------------------- 1 | var dfs = require('../../../src/graphs/searching/dfs').dfs; 2 | 3 | describe('dfs', function () { 4 | 'use strict'; 5 | 6 | it('should work with empty graph', function () { 7 | expect(dfs([[]])).toBeTruthy(); 8 | }); 9 | 10 | it('should always find a path between node and itself', function () { 11 | expect(dfs([[0]]), 0, 0).toBeTruthy(); 12 | }); 13 | 14 | it('should always find a path between two directly connected nodes', function () { 15 | expect(dfs([[0, 1], [1, 0]], 0, 1)).toBeTruthy(); 16 | expect(dfs([[0, 1], [1, 0]], 1, 0)).toBeTruthy(); 17 | }); 18 | 19 | it('should always find a path between two directly connected' + 20 | 'connected nodes in a directed graph', function () { 21 | expect(dfs([[0, 0], [1, 0]], 1, 0)).toBeTruthy(); 22 | }); 23 | 24 | it('should always find a path between two indirectly connected nodes', function () { 25 | expect(dfs([[0, 1, 0], [0, 0, 1], [0, 0, 0]], 0, 2)).toBeTruthy(); 26 | }); 27 | 28 | it('should not find a path between two nodes, which are not connected', function () { 29 | expect(dfs([[0, 0], [1, 0]], 0, 1)).toBeFalsy(); 30 | expect(dfs([[0, 0, 0], [0, 0, 1], [0, 0, 0]], 0, 2)).toBeFalsy(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/graphs/shortest-path/bellman-ford.spec.js: -------------------------------------------------------------------------------- 1 | var exported = 2 | require('../../../src/graphs/shortest-path/bellman-ford'); 3 | var bellmanFord = exported.bellmanFord; 4 | var Vertex = exported.Vertex; 5 | var Edge = exported.Edge; 6 | 7 | describe('Bellman-Ford', function () { 8 | 'use strict'; 9 | it('should exports a method called bellmanFord', function () { 10 | expect(typeof bellmanFord).toBe('function'); 11 | }); 12 | 13 | it('should work for an empty graph', function () { 14 | var vs = []; 15 | var e = []; 16 | expect(bellmanFord(vs, e, undefined)) 17 | .toEqual({ parents: {}, distances: {} }); 18 | }); 19 | 20 | it('should work for a graph with a single vertex', function () { 21 | var vs = [new Vertex(1)]; 22 | var e = []; 23 | expect(bellmanFord(vs, e, vs[0])) 24 | .toEqual({ parents: { 1: null }, distances: { 1: 0 }}); 25 | }); 26 | 27 | it('should work in the general case', function () { 28 | var vs = [new Vertex(1), new Vertex(2), new Vertex(3)]; 29 | var e = [new Edge(vs[0], vs[1], 2), 30 | new Edge(vs[0], vs[2], 10), 31 | new Edge(vs[1], vs[2], 1) 32 | ]; 33 | var output = bellmanFord(vs, e, vs[0]); 34 | expect(output.distances['3']).toBe(3); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/graphs/shortest-path/dijkstra.spec.js: -------------------------------------------------------------------------------- 1 | var dijkstra = 2 | require('../../../src/graphs/shortest-path/dijkstra').dijkstra; 3 | 4 | describe('dijkstra', function () { 5 | 'use strict'; 6 | it('should define a function', function () { 7 | expect(dijkstra).toBeDefined(); 8 | expect(typeof dijkstra).toBe('function'); 9 | }); 10 | 11 | it('should work with empty graph', function () { 12 | expect(dijkstra(0, 0, [])).toBe(Infinity); 13 | }); 14 | 15 | it('should work when the src and dest are the same', function () { 16 | expect(dijkstra(0, 0, [[0]])).toBe(0); 17 | }); 18 | 19 | it('should work when there\'s no path', function () { 20 | expect(dijkstra(0, 1, [[0, Infinity], [Infinity, 0]])).toBe(Infinity); 21 | }); 22 | 23 | it('should find the shortest path', function () { 24 | expect(dijkstra(0, 2, [[0, 1, 4], [1, 0, 1], [4, 1, 0]])).toBe(2); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/graphs/spanning-trees/kruskal.spec.js: -------------------------------------------------------------------------------- 1 | var kruskal = require('../../../src/graphs/spanning-trees/kruskal'); 2 | 3 | describe('Kruskal', function() { 4 | 'use strict'; 5 | 6 | it('should define a function', function () { 7 | expect(kruskal).toBeDefined(); 8 | expect(typeof kruskal).toBe('object'); 9 | expect(typeof kruskal.Graph).toBe('function'); 10 | expect(typeof kruskal.Edge).toBe('function'); 11 | expect(typeof kruskal.Vertex).toBe('function'); 12 | }); 13 | 14 | it('should work with an empty graph', function() { 15 | var graph = new kruskal.Graph([], 0); 16 | var spanningTree = graph.kruskal(); 17 | 18 | expect(spanningTree.edges.length).toEqual(0); 19 | }); 20 | 21 | it('should correctly compute general example', function() { 22 | var nodes = []; 23 | var edges = []; 24 | var i; 25 | for (i = 0; i < 7; i += 1) { 26 | nodes[i] = new kruskal.Vertex(i); 27 | } 28 | 29 | edges.push(new kruskal.Edge(nodes[0], nodes[1], 7)); 30 | edges.push(new kruskal.Edge(nodes[1], nodes[2], 8)); 31 | edges.push(new kruskal.Edge(nodes[2], nodes[4], 5)); 32 | edges.push(new kruskal.Edge(nodes[4], nodes[6], 9)); 33 | edges.push(new kruskal.Edge(nodes[5], nodes[6], 11)); 34 | edges.push(new kruskal.Edge(nodes[3], nodes[5], 6)); 35 | edges.push(new kruskal.Edge(nodes[0], nodes[3], 5)); 36 | edges.push(new kruskal.Edge(nodes[1], nodes[4], 7)); 37 | edges.push(new kruskal.Edge(nodes[1], nodes[3], 9)); 38 | edges.push(new kruskal.Edge(nodes[3], nodes[4], 15)); 39 | edges.push(new kruskal.Edge(nodes[4], nodes[5], 8)); 40 | 41 | var graph = new kruskal.Graph(edges); 42 | var spanningTree = graph.kruskal(); 43 | 44 | expect(spanningTree.edges.length).toEqual(6); 45 | 46 | var sum = spanningTree.edges.reduce(function(acc, edge) { 47 | return acc += edge.distance; 48 | }, 0); 49 | 50 | expect(sum).toEqual(39); 51 | 52 | }) 53 | }); 54 | -------------------------------------------------------------------------------- /test/others/fibonacci.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/others/fibonacci.js'); 2 | var fibonacci = mod.fibonacci; 3 | 4 | describe('fibonacci algorithm', function () { 5 | 'use strict'; 6 | 7 | it('should return value 1 with input 1.', function () { 8 | expect(fibonacci(1)).toBe(1); 9 | }); 10 | it('should return value 1 with input 2.', function () { 11 | expect(fibonacci(2)).toBe(1); 12 | }); 13 | it('should return value 2 with input 3.', function () { 14 | expect(fibonacci(3)).toBe(2); 15 | }); 16 | it('should return value 3 with input 4.', function () { 17 | expect(fibonacci(4)).toBe(3); 18 | }); 19 | it('should return value 5 with input 5.', function () { 20 | expect(fibonacci(5)).toBe(5); 21 | }); 22 | it('should be 83621143489848422977 with input 97.', function () { 23 | expect(fibonacci(97)).toBe(83621143489848422977); 24 | }); 25 | it('should throw when input is too large.', function () { 26 | expect(function () {fibonacci(98)}).toThrow('Input too large, results in inaccurate fibonacci value.'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/others/fibonacciMemory.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/others/fibonacciMemory.js'); 2 | var fibonacci = mod.fibonacciMemory; 3 | 4 | describe('fibonacci with Memory algorithm', function () { 5 | 'use strict'; 6 | 7 | it('should return value 1 with input 1.', function () { 8 | expect(fibonacci(1)).toBe(1); 9 | }); 10 | it('should return value 6 with input 8.', function () { 11 | expect(fibonacci(6)).toBe(8); 12 | }); 13 | it('should return value 7 with input 13.', function () { 14 | expect(fibonacci(7)).toBe(13); 15 | }); 16 | it('should return value 8 with input 21.', function () { 17 | expect(fibonacci(8)).toBe(21); 18 | }); 19 | it('should return value 9 with input 34.', function () { 20 | expect(fibonacci(9)).toBe(34); 21 | }); 22 | it('should return value 10 with input 55.', function () { 23 | expect(fibonacci(10)).toBe(55); 24 | }); 25 | it('should be 135301852344706760000 with input 98.', function () { 26 | expect(fibonacci(98)).toBe(135301852344706760000); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/others/levenshtein-distance.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/others/levenshtein-distance.js'); 2 | var levenshteinDistance = mod.levenshteinDistance; 3 | 4 | describe('Levenstein\'s minimum edit distance algorithm', function () { 5 | 'use strict'; 6 | 7 | it('should be defined', function () { 8 | expect(levenshteinDistance).toBeDefined(); 9 | }); 10 | 11 | it('"" -> "" should return 0.', function () { 12 | expect(levenshteinDistance('', '')).toBe(0); 13 | }); 14 | 15 | it('"T" -> "" should return 1.', function () { 16 | expect(levenshteinDistance('T', '')).toBe(1); 17 | }); 18 | 19 | it('"cake" -> "rake" should return 1.', function () { 20 | expect(levenshteinDistance('cake', 'rake')).toBe(1); 21 | }); 22 | 23 | it('"Sofia" -> "Sof" should return 2.', function () { 24 | expect(levenshteinDistance('Sofia', 'Sof')).toBe(2); 25 | }); 26 | 27 | it('"kitten" -> "sitting" should return 3', function () { 28 | expect(levenshteinDistance('kitten', 'sitting')).toBe(3); 29 | }); 30 | 31 | it('"google" -> "lookat" should return 4.', function () { 32 | expect(levenshteinDistance('google', 'lookat')).toBe(4); 33 | }); 34 | 35 | it('"emacs" -> "vim" should return 5.', function () { 36 | expect(levenshteinDistance('emacs', 'vim')).toBe(5); 37 | }); 38 | 39 | it('"coffee" -> "cocoa" should return 4.', function () { 40 | expect(levenshteinDistance('coffee', 'cocoa')).toBe(4); 41 | }); 42 | 43 | it('"Munich" -> "Muenchen" should return 4.', function () { 44 | expect(levenshteinDistance('Munich', 'Muenchen')).toBe(4); 45 | }); 46 | 47 | it('"rosebud" -> "budrose" should return 6.', function () { 48 | expect(levenshteinDistance('rosebud', 'budrose')).toBe(6); 49 | }); 50 | 51 | it('"decided" -> "decisive" should return 4.', function () { 52 | expect(levenshteinDistance('decided', 'decisive')).toBe(4); 53 | }); 54 | 55 | it('"similar" -> "simile" should return 2.', function () { 56 | expect(levenshteinDistance('similar', 'simile')).toBe(2); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/others/min-coins-sum.spec.js: -------------------------------------------------------------------------------- 1 | var minCoinsChange = 2 | require('../../src/others/min-coins-change.js').minCoinsChange; 3 | 4 | describe('Change making problem', function () { 5 | 'use strict'; 6 | 7 | it('should be defined', function () { 8 | expect(minCoinsChange).toBeDefined(); 9 | }); 10 | 11 | it('should work for 0 change', function () { 12 | expect(minCoinsChange([1, 2], 0)).toEqual([]); 13 | }); 14 | 15 | it('should work for change equals to array element', function () { 16 | expect(minCoinsChange([1, 2], 1)).toEqual([1]); 17 | }); 18 | 19 | it('should return the minimum amount of coins', function () { 20 | expect(minCoinsChange([1], 2)).toEqual([1, 1]); 21 | expect(minCoinsChange([1, 2], 3)).toEqual([1, 2]); 22 | // [2, 3, 2, 3] or [1, 3, 3, 3] 23 | expect(minCoinsChange([1, 2, 3], 10).length).toEqual(4); 24 | }); 25 | 26 | it('should return undefined for combination, which is not possible', function () { 27 | expect(minCoinsChange([1, 2, 3], 0.5)).not.toBeDefined(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/others/minkowski-distance.spec.js: -------------------------------------------------------------------------------- 1 | var mod = require('../../src/others/minkowski-distance.js'); 2 | var minkowskiDistance = mod.minkowskiDistance; 3 | 4 | describe('Minkowski Distance', function () { 5 | 'use strict'; 6 | 7 | it('should return 1 with points (0, 1), (1, 1) in order 1.', function () { 8 | expect(minkowskiDistance([0, 1], [1, 1], 1)).toBe(1); 9 | }); 10 | it('should return 2 with points (0, 1), (1, 1) in order 2.', function () { 11 | expect(minkowskiDistance([0, 1], [1, 1], 2)).toBe(1); 12 | }); 13 | it('should return 2 with points (0, 1, 4), (1, 1, 6) in order Positive Infinity.', function () { 14 | expect(minkowskiDistance([0, 1, 4], [1, 1, 6], Number.POSITIVE_INFINITY)).toBe(2); 15 | }); 16 | it('should return 0 with points (0, 1, 4), (1, 1, 6) in order Negative Infinity.', function () { 17 | expect(minkowskiDistance([0, 1, 4], [1, 1, 6], Number.NEGATIVE_INFINITY)).toBe(0); 18 | }); 19 | it('should return 8.372966759705923 with points (0, 3, 4, 5), (7, 6, 3, -1) in order 3.', function () { 20 | expect(minkowskiDistance([0, 3, 4, 5], [7, 6, 3, -1], 3)).toBe(8.372966759705923); 21 | }); 22 | it('should throw when both vectors don\'t have same dimension', function () { 23 | expect(function () { 24 | minkowskiDistance([1, 2], [1], 1) 25 | }).toThrow('Both vectors should have same dimension'); 26 | }); 27 | it('should throw when p is not defined', function () { 28 | expect(function () { 29 | minkowskiDistance([1, 2], [1, 2]) 30 | }).toThrow('The order "p" must be a number'); 31 | }); 32 | it('should throw when p is not a number', function () { 33 | expect(function () { 34 | minkowskiDistance([1, 2], [1, 2], NaN) 35 | }).toThrow('The order "p" must be a number'); 36 | }); 37 | it('should throw when p is less than 1', function () { 38 | expect(function () { 39 | minkowskiDistance([1, 2], [1, 2], 0) 40 | }).toThrow('Order less than 1 will violate the triangle inequality'); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/primes/is-prime.spec.js: -------------------------------------------------------------------------------- 1 | var isPrime = require('../../src/primes/is-prime').isPrime; 2 | 3 | describe('Advanced (optimised) method that checks number on prime', function () { 4 | 'use strict'; 5 | 6 | it('should give true for number 104743', function () { 7 | expect(isPrime(104743)).toBe(true); 8 | }); 9 | 10 | it('should give false for number 104744', function () { 11 | expect(isPrime(104744)).toBe(false); 12 | }); 13 | 14 | it('the 10001st prime number should be 104743', function () { 15 | var count = 1; //we know that 2 is prime 16 | var value = 1; 17 | 18 | while (count < 10001) { 19 | value += 2; 20 | 21 | if (isPrime(value)) { 22 | count += 1; 23 | } 24 | } 25 | 26 | expect(value).toEqual(104743); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/primes/prime-factor-tree.spec.js: -------------------------------------------------------------------------------- 1 | var primeFactorTree = require('../../src/primes/prime-factor-tree').primeFactorTree; 2 | 3 | describe('Prime factor tree', function () { 4 | 'use strict'; 5 | 6 | it('for number 104743 should return [104743]', function () { 7 | expect(primeFactorTree(104743).toString()).toEqual([104743].toString()); 8 | }); 9 | 10 | it('for number 18 should return [2, 3, 3]', function () { 11 | expect(primeFactorTree(18).toString()).toEqual([2, 3, 3].toString()); 12 | }); 13 | 14 | it('should give the empty list for number less or equal 1', function () { 15 | expect(primeFactorTree(-12).toString()).toEqual([].toString()); 16 | expect(primeFactorTree(0).toString()).toEqual([].toString()); 17 | expect(primeFactorTree(1).toString()).toEqual([].toString()); 18 | }); 19 | 20 | it('sum of primes for given number 600851475143 should be 9238', function () { 21 | var primes = primeFactorTree(600851475143); 22 | var sumOfPrimes = primes.reduce(function (previousValue, currentValue) { 23 | return previousValue + currentValue; 24 | }); 25 | 26 | expect(sumOfPrimes).toEqual(9238); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/primes/sieve-of-atkins.spec.js: -------------------------------------------------------------------------------- 1 | var sieveOfAtkins = 2 | require('../../src/primes/sieve-of-atkins').sieveOfAtkins; 3 | 4 | describe('Sieve Of Atkins', function () { 5 | 'use strict'; 6 | 7 | it('should give the right sequence of primes for limit 12', function () { 8 | expect(sieveOfAtkins(12).toString()) 9 | .toEqual([2, 3, 5, 7, 11].toString()); 10 | }); 11 | 12 | it('should give the empty list for limit less or equal 1', function () { 13 | expect(sieveOfAtkins(-12).toString()).toEqual([].toString()); 14 | expect(sieveOfAtkins(0).toString()).toEqual([].toString()); 15 | expect(sieveOfAtkins(1).toString()).toEqual([].toString()); 16 | }); 17 | 18 | it('sum of prime numbers up to 2000000 limit should be 142913828922', function () { 19 | var sieve = sieveOfAtkins(2000000); 20 | var sumOfPrimes = sieve.reduce(function (previousValue, currentValue) { 21 | return previousValue + currentValue; 22 | }); 23 | 24 | expect(sumOfPrimes).toEqual(142913828922); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/primes/sieve-of-eratosthenes.spec.js: -------------------------------------------------------------------------------- 1 | var sieveOfEratosthenes = 2 | require('../../src/primes/sieve-of-eratosthenes').sieveOfEratosthenes; 3 | 4 | describe('Sieve Of Eratosthenes', function () { 5 | 'use strict'; 6 | 7 | it('should give the right sequence of primes for limit 12', function () { 8 | expect(sieveOfEratosthenes(12).toString()) 9 | .toEqual([2, 3, 5, 7, 11].toString()); 10 | }); 11 | 12 | it('should give the empty list for limit less or equal 1', function () { 13 | expect(sieveOfEratosthenes(-12).toString()).toEqual([].toString()); 14 | expect(sieveOfEratosthenes(0).toString()).toEqual([].toString()); 15 | expect(sieveOfEratosthenes(1).toString()).toEqual([].toString()); 16 | }); 17 | 18 | it('sum of prime numbers up to 2000000 limit should be 142913828922', function () { 19 | var sieve = sieveOfEratosthenes(2000000); 20 | var sumOfPrimes = sieve.reduce(function (previousValue, currentValue) { 21 | return previousValue + currentValue; 22 | }); 23 | 24 | expect(sumOfPrimes).toEqual(142913828922); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/searching/binarysearch.spec.js: -------------------------------------------------------------------------------- 1 | var binarySearch = 2 | require('../../src/searching/binarysearch').binarySearch; 3 | 4 | describe('Binary search', function () { 5 | 'use strict'; 6 | 7 | it('should find the element at position 0 ', function () { 8 | expect(binarySearch([1, 2, 3, 4, 6, 8], 1)).toBe(0); 9 | }); 10 | 11 | it('should find the element in position arr.length - 1', function () { 12 | var arr = [1, 2, 3, 4, 6, 8]; 13 | expect(binarySearch(arr, 8)).toBe(arr.length - 1); 14 | }); 15 | 16 | it('should work with arrays with 2 elements', function () { 17 | expect(binarySearch([1, 8], 1)).toBe(0); 18 | expect(binarySearch([1, 8], 8)).toBe(1); 19 | }); 20 | 21 | it('should return a negative number for missing elements', function () { 22 | expect(binarySearch([1, 2, 3], 4)).toBeLessThan(0); 23 | }); 24 | 25 | it('should work with empty arrays', function () { 26 | expect(binarySearch([], 4)).toBe(-1); 27 | }); 28 | 29 | it('should work with a key string', function () { 30 | expect(binarySearch([{ x: 1 }, { x: 2 }, { x: 3 }], { x: 2 }, 'x')).toBe(1); 31 | }); 32 | 33 | it('should work with a key function', function () { 34 | expect(binarySearch([{ x: 1 }, { x: 2 }, { x: 3 }], 35 | { x: 2 }, function (o) { return o.x; })).toBe(1); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/searching/interpolation-search.spec.js: -------------------------------------------------------------------------------- 1 | var interpolationSearch = require('../../src/searching/interpolation-search') 2 | .interpolationSearch; 3 | 4 | describe('Interpolation search', function() { 5 | 'use strict'; 6 | 7 | it('should find the element at position 0 ', function() { 8 | expect(interpolationSearch([1, 2, 3, 4, 6, 8], 1)).toBe(0); 9 | }); 10 | 11 | it('should find the element at position 4 ', function() { 12 | expect(interpolationSearch([1, 2, 3, 4, 6, 8], 6)).toBe(4); 13 | }); 14 | 15 | it('should return -1 if element is not found', function() { 16 | expect(interpolationSearch([1, 2, 3, 4, 6, 8], 17)).toBe(-1); 17 | }); 18 | 19 | it('should return -1 if array is empty', function() { 20 | expect(interpolationSearch([], 10)).toBe(-1); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/searching/jump-search.spec.js: -------------------------------------------------------------------------------- 1 | var jumpSearch = require('../../src/searching/jump-search').jumpSearch; 2 | 3 | describe('Jump search', function() { 4 | 'use strict'; 5 | 6 | it('should find the element at position 0 ', function() { 7 | expect(jumpSearch([1, 2, 3, 4, 6, 8], 1)).toBe(0); 8 | }); 9 | 10 | it('should find the element at position 4 ', function() { 11 | expect(jumpSearch([1, 2, 3, 4, 6, 8], 6)).toBe(4); 12 | }); 13 | 14 | it('should return -1 ', function() { 15 | expect(jumpSearch([1, 2, 3, 4, 6, 8], 10)).toBe(-1); 16 | }); 17 | 18 | it('should return -1 ', function() { 19 | expect(jumpSearch([], 10)).toBe(-1); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/searching/knuth-morris-pratt.spec.js: -------------------------------------------------------------------------------- 1 | var indexOf = require('../../src/searching/knuth-morris-pratt').kmp; 2 | 3 | describe('The string searching algorithm of Knuth-Morris-Pratt', function () { 4 | 'use strict'; 5 | 6 | it('should find the empty string in any string', function () { 7 | expect(indexOf('', '')).toBe(0); 8 | expect(indexOf('foo', '')).toBe(0); 9 | }); 10 | 11 | it('should return negative value for patterns, which are ' + 12 | 'not part of the string', function () { 13 | expect(indexOf('foo', 'bar') < 0).toBeTruthy(); 14 | expect(indexOf('f', 'foobar') < 0).toBeTruthy(); 15 | expect(indexOf('foobar', 'fobar') < 0).toBeTruthy(); 16 | }); 17 | 18 | it('should return the first index of the matching pattern', function () { 19 | expect(indexOf('foo', 'f')).toBe(0); 20 | expect(indexOf('foo', 'oo')).toBe(1); 21 | expect(indexOf('foo', 'o')).toBe(1); 22 | expect(indexOf('foobar', 'foo')).toBe(0); 23 | expect(indexOf('foobar', 'bar')).toBe(3); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/searching/linearSearch.spec.js: -------------------------------------------------------------------------------- 1 | var linearSearch = 2 | require('../../src/searching/linearSearch').linearSearch; 3 | 4 | describe('Linear Search', function () { 5 | 'use strict'; 6 | 7 | it('should find the element at position 0 ', function () { 8 | expect(linearSearch([1, 2, 3, 4, 6, 8], 1)).toBe(0); 9 | }); 10 | 11 | it('should find the element in position arr.length - 1', function () { 12 | var arr = [1, 2, 3, 4, 6, 8]; 13 | expect(linearSearch(arr, 8)).toBe(arr.length - 1); 14 | }); 15 | 16 | it('should work with arrays with 2 elements', function () { 17 | expect(linearSearch([1, 8], 1)).toBe(0); 18 | expect(linearSearch([1, 8], 8)).toBe(1); 19 | }); 20 | 21 | it('should return a negative number for missing elements', function () { 22 | expect(linearSearch([1, 2, 3], 4)).toBeLessThan(0); 23 | }); 24 | 25 | it('should work with empty arrays', function () { 26 | expect(linearSearch([], 4)).toBe(-1); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/searching/longest-common-subsequence.spec.js: -------------------------------------------------------------------------------- 1 | var longestCommonSubsequence = 2 | require('../../src/searching/' + 3 | 'longest-common-subsequence') 4 | .longestCommonSubsequence; 5 | 6 | describe('longest common subsequence', function () { 7 | 'use strict'; 8 | 9 | it('should work with empty strings', function () { 10 | expect(longestCommonSubsequence('', '')).toBe(''); 11 | }); 12 | 13 | it('should work with first string empty', function () { 14 | expect(longestCommonSubsequence('', 'abcd')).toBe(''); 15 | }); 16 | 17 | it('should work with second string empty', function () { 18 | expect(longestCommonSubsequence('abcd', '')).toBe(''); 19 | }); 20 | 21 | it('should work if there is no lcs', function () { 22 | expect(longestCommonSubsequence('qtwer', 'zvxcv')).toBe(''); 23 | }); 24 | 25 | it('should work if lcs is whole first string', function () { 26 | expect(longestCommonSubsequence('abc', 'abcdefghi')).toBe('abc'); 27 | }); 28 | 29 | it('should work if lcs is whole second string', function () { 30 | expect(longestCommonSubsequence('qwerty', 'rty')).toBe('rty'); 31 | }); 32 | 33 | it('should work with repeated letter', function () { 34 | expect(longestCommonSubsequence('AAATC', 'GGTAGGC')).toBe('AC'); 35 | }); 36 | 37 | it('should work with custom characters', function () { 38 | expect(longestCommonSubsequence(':-)', 'B-)')).toBe('-)'); 39 | }); 40 | 41 | it('should work with long strings', function () { 42 | expect(longestCommonSubsequence('this is the first string', 'that is second')).toBe('tht is sn'); 43 | }); 44 | 45 | it('should work with very long strings', function () { 46 | expect(longestCommonSubsequence('giiiiiiit1huuuuuu2bbb', 'zzxxcvasdfgmntplpliiggggu2b222')).toBe('giiu2b'); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/searching/longest-increasing-subsequence.spec.js: -------------------------------------------------------------------------------- 1 | var longestIncreasingSubsequence = 2 | require('../../src/searching/' + 3 | 'longest-increasing-subsequence') 4 | .longestIncreasingSubsequence; 5 | 6 | describe('longest increasing subsequence', function () { 7 | 'use strict'; 8 | 9 | var sequence; 10 | beforeEach(function () { 11 | sequence = [5, 2, 8, 6, 3, 6, 9, 7, 11]; 12 | }); 13 | 14 | it('should work with empty array', function () { 15 | expect(longestIncreasingSubsequence([]).length).toBe(0); 16 | }); 17 | 18 | it('should return the only element in a single element array', function () { 19 | var array = [1]; 20 | expect(longestIncreasingSubsequence(array)).toEqual([1]); 21 | }); 22 | 23 | it('should give the right length', function () { 24 | expect(longestIncreasingSubsequence(sequence).length).toBe(5); 25 | }); 26 | 27 | it('should work with empty arrays', function () { 28 | expect(longestIncreasingSubsequence([]).length).toBe(0); 29 | }); 30 | 31 | it('should return the correct path', function () { 32 | expect(longestIncreasingSubsequence(sequence).toString()) 33 | .toBe([2, 3, 6, 9, 11].toString()); 34 | }); 35 | 36 | it('should work with a custom comparator', function () { 37 | var cmp = function (a, b) { 38 | return b - a; 39 | }; 40 | var seq = [1, 2, -1]; 41 | var result = longestIncreasingSubsequence(seq, cmp); 42 | expect(result.length).toBe(2); 43 | expect(result).toEqual([1, -1]); 44 | }); 45 | }); 46 | 47 | -------------------------------------------------------------------------------- /test/searching/maximum-subarray-divide-and-conquer.spec.js: -------------------------------------------------------------------------------- 1 | var maxSubArray = 2 | require('../../src/searching/maximum-subarray-divide-and-conquer') 3 | .maxSubarray; 4 | 5 | describe('Maximum subarray implemented with divide and conquer', function () { 6 | 'use strict'; 7 | 8 | it('should work with empty arrays', function () { 9 | expect(isNaN(maxSubArray([]))).toBeTruthy(); 10 | }); 11 | 12 | it('should return the only element when an array with' + 13 | 'single element is passed', function () { 14 | expect(maxSubArray([42])).toBe(42); 15 | }); 16 | 17 | it('should return the only negative element when an array with' + 18 | 'single element is passed', function () { 19 | expect(maxSubArray([-42])).toBe(-42); 20 | }); 21 | 22 | it('should return the zero when an array with' + 23 | 'single element, which is zero is passed', function () { 24 | expect(maxSubArray([0])).toBe(0); 25 | }); 26 | 27 | it('should return the max sum of a subarray', function () { 28 | expect(maxSubArray([1, -1, 2, 3, -1])).toBe(5); 29 | }); 30 | 31 | it('should return the max nevative number when array' + 32 | 'with nevative numbers is provided', function () { 33 | expect(maxSubArray([-10, -1, -2, -3, -1])).toBe(-1); 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/searching/maximum-subarray.spec.js: -------------------------------------------------------------------------------- 1 | var maxSubArray = require('../../src/searching/maximum-subarray').maxSubarray; 2 | 3 | describe('Maximum subarray', function() { 4 | 'use strict'; 5 | 6 | it('should work with empty arrays', function() { 7 | expect(maxSubArray([])).toBeUndefined(); 8 | }); 9 | 10 | it('should return the only element when an array with single element is passed', function() { 11 | expect(maxSubArray([42])).toBe(42); 12 | }); 13 | 14 | it('should return the only negative element when an array with single element is passed', function() { 15 | expect(maxSubArray([-42])).toBe(-42); 16 | }); 17 | 18 | it('should return the zero when an array with single element, which is zero is passed', function() { 19 | expect(maxSubArray([0])).toBe(0); 20 | }); 21 | 22 | it('should return the max sum of a subarray', function() { 23 | expect(maxSubArray([1, -1, 2, 3, -1])).toBe(5); 24 | }); 25 | 26 | it('should return the max negative number when array with negative numbers is provided', function() { 27 | expect(maxSubArray([-10, -1, -2, -3, -1])).toBe(-1); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/searching/quickselect.spec.js: -------------------------------------------------------------------------------- 1 | var quickselect = require('../../src/searching/quickselect').quickselect; 2 | 3 | describe('quickselect', function () { 4 | 'use strict'; 5 | 6 | it('should be defined as function', function () { 7 | expect(typeof quickselect).toBe('function'); 8 | }); 9 | 10 | it('should work with empty array', function () { 11 | expect(quickselect([], 1)).toBe(undefined); 12 | }); 13 | 14 | it('should find the only element in the list', function () { 15 | expect(quickselect([1], 0)).toBe(1); 16 | }); 17 | 18 | it('should return undefined if the list is smaller than the index', 19 | function () { 20 | expect(quickselect([2, 1], 3)).toBeUndefined(); 21 | }); 22 | 23 | it('should find the element if in sorted order', function () { 24 | expect(quickselect([1, 2], 0)).toBe(1); 25 | expect(quickselect([1, 2], 1)).toBe(2); 26 | }); 27 | 28 | it('should fine the element if not in sorted order', function () { 29 | expect(quickselect([2, 1, 9, 6], 3)).toBe(9); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/searching/recursive-binarysearch.spec.js: -------------------------------------------------------------------------------- 1 | var binarySearch = 2 | require('../../src/searching/recursive-binarysearch').binarySearch; 3 | 4 | describe('Binary search', function () { 5 | 'use strict'; 6 | 7 | it('should find the element at position 0 ', function () { 8 | expect(binarySearch([1, 2, 3, 4, 6, 8], 1)).toBe(0); 9 | }); 10 | 11 | it('should find the eleent in position arr.length', function () { 12 | expect(binarySearch([1, 2, 3, 4, 6, 8], 1)).toBe(0); 13 | }); 14 | 15 | it('should work with arrays with 2 elements', function () { 16 | expect(binarySearch([1, 8], 1)).toBe(0); 17 | expect(binarySearch([1, 8], 8)).toBe(1); 18 | }); 19 | 20 | it('should return a negative number for missing elements', function () { 21 | expect(binarySearch([1, 2, 3], 4)).toBeLessThan(0); 22 | }); 23 | 24 | it('should work with empty arrays', function () { 25 | expect(binarySearch([], 4)).toBe(-1); 26 | }); 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /test/sorting/3-way-string-quicksort.spec.js: -------------------------------------------------------------------------------- 1 | var quicksort = 2 | require('../../src/sorting/3-way-string-quicksort.js').quicksort; 3 | 4 | describe('Most-Significant Digit', function () { 5 | 'use strict'; 6 | 7 | it('should work with empty arrays', function () { 8 | expect(quicksort([]).length).toBe(0); 9 | }); 10 | 11 | it('should work with arrays with a single element', function () { 12 | var arr = ['a']; 13 | quicksort(arr); 14 | expect(arr.length).toBe(1); 15 | expect(arr[0]).toBe('a'); 16 | }); 17 | 18 | it('should work with arrays with equally length strings', function () { 19 | var arr = ['bb', 'aa', 'cc']; 20 | quicksort(arr); 21 | expect(arr.length).toBe(3); 22 | expect(arr[0]).toBe('aa'); 23 | expect(arr[1]).toBe('bb'); 24 | expect(arr[2]).toBe('cc'); 25 | }); 26 | 27 | it('should work with arrays with differently length strings', function () { 28 | var arr = ['bb', 'aaa', 'a', 'aa']; 29 | quicksort(arr); 30 | expect(arr.length).toBe(4); 31 | expect(arr[0]).toBe('a'); 32 | expect(arr[1]).toBe('aa'); 33 | expect(arr[2]).toBe('aaa'); 34 | expect(arr[3]).toBe('bb'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/sorting/bubblesort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var bubbleSort = 3 | require('../../src/sorting/bubblesort.js').bubbleSort; 4 | 5 | sortTestCase(bubbleSort, 'Bubble sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/bucketsort.spec.js: -------------------------------------------------------------------------------- 1 | var bs = 2 | require('../../src/sorting/bucketsort').bucketSort; 3 | 4 | describe('bucketsort', function () { 5 | 'use strict'; 6 | 7 | it('should sort the empty array', function () { 8 | expect(bs([])).toEqual([]); 9 | }); 10 | 11 | it('should return array with the same count of elements', function () { 12 | expect(bs([2, 3, 4]).length).toBe(3); 13 | }); 14 | 15 | it('should sort the given array in ascending order', function () { 16 | expect(bs([42, 3, 10])).toEqual([3, 10, 42]); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/sorting/countingsort.spec.js: -------------------------------------------------------------------------------- 1 | var cs = 2 | require('../../src/sorting/countingsort').countingSort; 3 | 4 | describe('countingsort', function () { 5 | 'use strict'; 6 | 7 | it('should sort the empty array', function () { 8 | expect(cs([])).toEqual([]); 9 | }); 10 | 11 | it('should return array with the same count of elements', function () { 12 | expect(cs([2, 3, 4]).length).toBe(3); 13 | }); 14 | 15 | it('should sort the given array in ascending order', function () { 16 | expect(cs([42, 3, 10])).toEqual([3, 10, 42]); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/sorting/heapsort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var heapSort = require('../../src/sorting/heapsort.js').heapSort; 3 | 4 | sortTestCase(heapSort, 'Heap sort'); 5 | -------------------------------------------------------------------------------- /test/sorting/insertionbinarysort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var insertionBinarySort = 3 | require('../../src/sorting/' + 4 | 'insertion-binary-sort.js').insertionBinarySort; 5 | 6 | sortTestCase(insertionBinarySort, 'Insertion binary sort'); 7 | -------------------------------------------------------------------------------- /test/sorting/insertionsort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var insertionSort = require('../../src/sorting/' + 3 | 'insertionsort.js').insertionSort; 4 | 5 | sortTestCase(insertionSort, 'Insertion sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/lsd.spec.js: -------------------------------------------------------------------------------- 1 | var lsd = require('../../src/sorting/lsd.js').lsd; 2 | 3 | describe('Least-Significant Digit', function () { 4 | 'use strict'; 5 | 6 | it('should work with empty arrays', function () { 7 | expect(lsd([]).length).toBe(0); 8 | }); 9 | 10 | it('should work with arrays with a single element', function () { 11 | var arr = ['a']; 12 | lsd(arr); 13 | expect(arr.length).toBe(1); 14 | expect(arr[0]).toBe('a'); 15 | }); 16 | 17 | it('should work with arrays with equally length strings', function () { 18 | var arr = ['bb', 'aa', 'cc']; 19 | lsd(arr); 20 | expect(arr.length).toBe(3); 21 | expect(arr[0]).toBe('aa'); 22 | expect(arr[1]).toBe('bb'); 23 | expect(arr[2]).toBe('cc'); 24 | }); 25 | 26 | it('should work with arrays with equally length strings', function () { 27 | var arr = ['bbb', 'aac', 'aaa']; 28 | lsd(arr, 3); 29 | expect(arr.length).toBe(3); 30 | expect(arr[0]).toBe('aaa'); 31 | expect(arr[1]).toBe('aac'); 32 | expect(arr[2]).toBe('bbb'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/sorting/mergesort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var mergeSort = 3 | require('../../src/sorting/mergesort.js').mergeSort; 4 | 5 | sortTestCase(mergeSort, 'Merge sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/msd.spec.js: -------------------------------------------------------------------------------- 1 | var msd = require('../../src/sorting/msd.js').msd; 2 | 3 | describe('Most-Significant Digit', function () { 4 | 'use strict'; 5 | 6 | it('should work with empty arrays', function () { 7 | expect(msd([]).length).toBe(0); 8 | }); 9 | 10 | it('should work with arrays with a single element', function () { 11 | var arr = ['a']; 12 | msd(arr); 13 | expect(arr.length).toBe(1); 14 | expect(arr[0]).toBe('a'); 15 | }); 16 | 17 | it('should work with arrays with equally length strings', function () { 18 | var arr = ['bb', 'aa', 'cc']; 19 | msd(arr); 20 | expect(arr.length).toBe(3); 21 | expect(arr[0]).toBe('aa'); 22 | expect(arr[1]).toBe('bb'); 23 | expect(arr[2]).toBe('cc'); 24 | }); 25 | 26 | it('should work with arrays with differently length strings', function () { 27 | var arr = ['bb', 'aaa', 'a', 'aa']; 28 | msd(arr); 29 | expect(arr.length).toBe(4); 30 | expect(arr[0]).toBe('a'); 31 | expect(arr[1]).toBe('aa'); 32 | expect(arr[2]).toBe('aaa'); 33 | expect(arr[3]).toBe('bb'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/sorting/oddeven-sort.spec.js: -------------------------------------------------------------------------------- 1 | var oes = 2 | require('../../src/sorting/oddeven-sort').oddEvenSort; 3 | 4 | describe('oddeven-sort', function () { 5 | 'use strict'; 6 | 7 | it('should sort the empty array', function () { 8 | expect(oes([])).toEqual([]); 9 | }); 10 | 11 | it('should return array with the same count of elements', function () { 12 | expect(oes([2, 3, 4]).length).toBe(3); 13 | }); 14 | 15 | it('should sort the given array in ascending order', function () { 16 | expect(oes([42, 3, 10])).toEqual([3, 10, 42]); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/sorting/quicksort-declarative.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var quickSort = 3 | require('../../src/sorting/quicksort-declarative.js').quickSort; 4 | 5 | sortTestCase(quickSort, 'Quick sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/quicksort-middle.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var quickSort = 3 | require('../../src/sorting/quicksort-middle.js').quickSort; 4 | 5 | sortTestCase(quickSort, 'Quick sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/quicksort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var quickSort = 3 | require('../../src/sorting/quicksort.js').quickSort; 4 | 5 | sortTestCase(quickSort, 'Quick sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/radixsort.spec.js: -------------------------------------------------------------------------------- 1 | var rx = 2 | require('../../src/sorting/radixsort.js').radixSort; 3 | 4 | describe('radixsort', function () { 5 | 'use strict'; 6 | 7 | it('should sort the empty array', function () { 8 | expect(rx([])).toEqual([]); 9 | }); 10 | 11 | it('should return array with the same count of elements', function () { 12 | expect(rx([2, 3, 4]).length).toBe(3); 13 | }); 14 | 15 | it('should sort the given array in ascending order', function () { 16 | expect(rx([42, 3, 10])).toEqual([3, 10, 42]); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/sorting/recursiveinsertionsort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var recursiveInsertionSort = require('../../src/sorting/' + 3 | 'recursive-insertionsort.js').recursiveInsertionSort; 4 | 5 | sortTestCase(recursiveInsertionSort, 'Recursive insertion sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/selectionsort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var selectionSort = 3 | require('../../src/sorting/selectionsort.js') 4 | .selectionSort; 5 | 6 | sortTestCase(selectionSort, 'Selection sort'); 7 | -------------------------------------------------------------------------------- /test/sorting/shellsort.spec.js: -------------------------------------------------------------------------------- 1 | var sortTestCase = require('./sort.testcase.js'); 2 | var shellSort = require('../../src/sorting/shellsort.js') 3 | .shellSort; 4 | 5 | sortTestCase(shellSort, 'Shell sort'); 6 | -------------------------------------------------------------------------------- /test/sorting/sort.testcase.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sort, algorithmName, options) { 2 | 'use strict'; 3 | 4 | options = options || { 5 | integers: false, 6 | reverse: true 7 | }; 8 | 9 | describe(algorithmName, function () { 10 | 11 | function createRandomArray(config) { 12 | config = config || {}; 13 | var size = config.size || 100; 14 | var precision = config.precision || 2; 15 | var multiplier = config.multiplier || 100; 16 | var result = []; 17 | 18 | for (var i = size; i > 0; i -= 1) { 19 | result.push(parseFloat((Math.random() * 20 | multiplier).toFixed(precision))); 21 | } 22 | return result; 23 | } 24 | 25 | it('should work with empty array', function () { 26 | expect(sort([])).toEqual([]); 27 | }); 28 | 29 | it('should work with sorted arrays', function () { 30 | expect(sort([1, 2, 3, 4])).toEqual([1, 2, 3, 4]); 31 | }); 32 | 33 | it('should work with random non-sorted arrays', function () { 34 | var array; 35 | if (options.integers) { 36 | array = createRandomArray(); 37 | } else { 38 | array = createRandomArray({ 39 | precision: 0 40 | }); 41 | } 42 | array = sort(array); 43 | for (var i = 0; i < array.length - 1; i += 1) { 44 | expect(array[i] <= array[i + 1]).toBeTruthy(); 45 | } 46 | }); 47 | 48 | if (options.reverse) { 49 | it('should sort the numbers in descending order ' + 50 | 'when such comparator is provided', function () { 51 | function comparator(a, b) { 52 | return b - a; 53 | } 54 | 55 | var array = createRandomArray(); 56 | array = sort(array, comparator); 57 | 58 | for (var i = 0; i < array.length - 1; i += 1) { 59 | expect(array[i] >= array[i + 1]).toBeTruthy(); 60 | } 61 | }); 62 | } 63 | 64 | }); 65 | }; 66 | --------------------------------------------------------------------------------