├── .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 |
--------------------------------------------------------------------------------