Showing preview only (364K chars total). Download the full file or copy to clipboard to get everything.
Repository: mgechev/javascript-algorithms
Branch: master
Commit: 405279c52e6a
Files: 150
Total size: 329.1 KB
Directory structure:
gitextract_q50stgoz/
├── .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
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"env": {
"browser": true,
"jquery": true,
"node": true,
"es6": true
},
"globals": {
"expect": true,
"it": true,
"describe": true,
"beforeEach": true,
"afterEach": true
},
"parserOptions": {
"ecmaVersion": 6
},
"rules": {
"camelcase": 2,
"eqeqeq": 2,
"indent": [
2,
2,
{
"SwitchCase": 1
}
],
"no-use-before-define": [
2,
{
"functions": false
}
],
"no-caller": 2,
"new-cap": 0,
"quotes": [
2,
"single"
],
"no-unused-vars": 2,
"strict": [
2,
"function"
],
"no-extend-native": 2,
"wrap-iife": [
2,
"any"
],
"no-empty": 2,
"no-plusplus": 2,
"no-undef": 2,
"linebreak-style": 0,
"max-depth": [
2,
4
],
"no-loop-func": 2,
"complexity": [
2,
13
],
"max-len": [
2,
{
"code": 120,
"ignoreComments": true
}
],
"max-params": [
2,
5
],
"curly": [
2,
"all"
],
"keyword-spacing": [
2,
{}
],
"one-var": [
2,
"never"
],
"array-bracket-spacing": [
2,
"never",
{}
],
"space-in-parens": [
2,
"never"
],
"key-spacing": [
2,
{
"beforeColon": false,
"afterColon": true
}
],
"quote-props": [
2,
"as-needed"
],
"space-infix-ops": 2,
"space-unary-ops": [
2,
{
"words": false,
"nonwords": false
}
],
"no-implicit-coercion": [
2,
{
"boolean": false,
"string": true,
"number": true
}
],
"no-with": 2,
"no-multiple-empty-lines": 2,
"brace-style": [
2,
"1tbs",
{
"allowSingleLine": true
}
],
"eol-last": 2,
"no-trailing-spaces": 2
}
}
================================================
FILE: .github/workflows/main.yml
================================================
name: Node.js CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '17.7.x'
- run: yarn --frozen-lockfile
- run: npm test
================================================
FILE: .gitignore
================================================
node_modules
.vscode
npm-debug.log
debug
dist
.idea
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- "8"
script: npm run build
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at minko@gechev.io. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Minko Gechev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: doc-config.json
================================================
{
"tags": {
"allowUnknownTags": true
},
"source": {
"include": [
"./src/combinatorics/",
"./src/compression/",
"./src/data-structures/",
"./src/graphics/",
"./src/graphs/others/",
"./src/graphs/searching/",
"./src/graphs/shortest-path/",
"./src/graphs/spanning-trees/",
"./src/others/",
"./src/primes/",
"./src/searching/",
"./src/sets/",
"./src/shuffle/",
"./src/sorting/"
],
"includePattern": ".+\\.js(doc)?$",
"excludePattern": "docs"
},
"plugins": [],
"opts": {
"template": "node_modules/@jeremyckahn/minami",
"encoding": "utf8",
"destination": "dist",
"recurse": true,
"private": false,
"readme": "./readme.md"
}
}
================================================
FILE: gulpfile.js
================================================
const gulp = require('gulp');
const eslint = require('gulp-eslint');
const jasmine = require('gulp-jasmine');
gulp.task('test', () => {
'use strict';
return gulp.src('test/**/*.spec.js')
.pipe(jasmine());
});
gulp.task('lint', ()=> {
'use strict';
return gulp.src(['src/**/*.js', 'test/**/*.js'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
gulp.task('build', gulp.parallel(['lint', 'test']));
================================================
FILE: package.json
================================================
{
"name": "javascript-algorithms",
"version": "0.0.0",
"description": "Implementations of different computer science algorithms",
"main": "index.js",
"directories": {
"test": "test"
},
"devDependencies": {
"@jeremyckahn/minami": "^1.3.1",
"gh-pages": "^1.1.0",
"gulp": "^4.0.2",
"gulp-eslint": "^3.0.1",
"gulp-jasmine": "^2.0.1",
"jsdoc": "3.5.5",
"live-server": "^1.2.0"
},
"scripts": {
"build": "gulp build",
"test": "gulp test",
"deploy": "npm run doc:build && gh-pages -d dist -b gh-pages",
"doc": "npm run doc:build && npm run doc:view",
"doc:build": "jsdoc -c doc-config.json",
"doc:view": "live-server dist --port=9124"
},
"repository": {
"type": "git",
"url": "git://github.com/mgechev/javascript-algorithms"
},
"author": "@mgechev",
"license": "MIT",
"bugs": {
"url": "https://github.com/mgechev/javascript-algorithms/issues"
},
"homepage": "https://github.com/mgechev/javascript-algorithms"
}
================================================
FILE: readme.md
================================================
## About
This repository contains JavaScript implementations of famous computer science algorithms.
API reference with usage examples available
<a href="https://mgechev.github.io/javascript-algorithms/" target="_blank">here</a>.
## Development
**To install all dev dependencies**
Call:
```bash
npm install
```
**To setup repository with documentation**
```bash
npm run doc
```
This will build the documentation and open it in your browser.
**To update .html files with documentation**
Just run `npm run doc` again.
**To run tests**
Call:
```bash
npm run test
```
This will execute all `*.spec.js` files.
**To deploy documentation site**
```bash
npm run deploy
```
This requires you to have commit access to your Git remote.
## Contributions
Fork the repo and make required changes. Afterwards, push your changes in branch. The name will be according to the changes you did. Initiate the pull request.
Make sure your editor makes validations according to the `.jshintrc` in the root directory of the repository.
Before pushing to the repository, run:
```bash
npm run build
```
If the build is not successful, fix your code in order for the tests and jshint validation to run successfully. Then create a pull request.
## Contributors
[<img alt="mgechev" src="https://avatars1.githubusercontent.com/u/455023?v=4&s=117" width="117">](https://github.com/mgechev) |[<img alt="AndriiHeonia" src="https://avatars1.githubusercontent.com/u/773648?v=4&s=117" width="117">](https://github.com/AndriiHeonia) |[<img alt="Jakehp" src="https://avatars1.githubusercontent.com/u/1854569?v=4&s=117" width="117">](https://github.com/Jakehp) |[<img alt="lygstate" src="https://avatars3.githubusercontent.com/u/121040?v=4&s=117" width="117">](https://github.com/lygstate) |[<img alt="mik-laj" src="https://avatars1.githubusercontent.com/u/12058428?v=4&s=117" width="117">](https://github.com/mik-laj) |[<img alt="krzysztof-grzybek" src="https://avatars0.githubusercontent.com/u/6236664?v=4&s=117" width="117">](https://github.com/krzysztof-grzybek) |
:---: |:---: |:---: |:---: |:---: |:---: |
[mgechev](https://github.com/mgechev) |[AndriiHeonia](https://github.com/AndriiHeonia) |[Jakehp](https://github.com/Jakehp) |[lygstate](https://github.com/lygstate) |[mik-laj](https://github.com/mik-laj) |[krzysztof-grzybek](https://github.com/krzysztof-grzybek) |
[<img alt="pvoznenko" src="https://avatars3.githubusercontent.com/u/1098414?v=4&s=117" width="117">](https://github.com/pvoznenko) |[<img alt="jettcalleja" src="https://avatars0.githubusercontent.com/u/6356258?v=4&s=117" width="117">](https://github.com/jettcalleja) |[<img alt="filipefalcaos" src="https://avatars2.githubusercontent.com/u/9125631?v=4&s=117" width="117">](https://github.com/filipefalcaos) |[<img alt="kdamball" src="https://avatars3.githubusercontent.com/u/3318312?v=4&s=117" width="117">](https://github.com/kdamball) |[<img alt="lekkas" src="https://avatars3.githubusercontent.com/u/5211478?v=4&s=117" width="117">](https://github.com/lekkas) |[<img alt="infusion" src="https://avatars3.githubusercontent.com/u/197742?v=4&s=117" width="117">](https://github.com/infusion) |
:---: |:---: |:---: |:---: |:---: |:---: |
[pvoznenko](https://github.com/pvoznenko) |[jettcalleja](https://github.com/jettcalleja) |[filipefalcaos](https://github.com/filipefalcaos) |[kdamball](https://github.com/kdamball) |[lekkas](https://github.com/lekkas) |[infusion](https://github.com/infusion) |
[<img alt="deniskyashif" src="https://avatars2.githubusercontent.com/u/5999271?v=4&s=117" width="117">](https://github.com/deniskyashif) |[<img alt="brunohadlich" src="https://avatars2.githubusercontent.com/u/7043013?v=4&s=117" width="117">](https://github.com/brunohadlich) |[<img alt="designeng" src="https://avatars0.githubusercontent.com/u/2807469?v=4&s=117" width="117">](https://github.com/designeng) |[<img alt="Microfed" src="https://avatars1.githubusercontent.com/u/613179?v=4&s=117" width="117">](https://github.com/Microfed) |[<img alt="Nirajkashyap" src="https://avatars3.githubusercontent.com/u/4338110?v=4&s=117" width="117">](https://github.com/Nirajkashyap) |[<img alt="pkerpedjiev" src="https://avatars3.githubusercontent.com/u/2143629?v=4&s=117" width="117">](https://github.com/pkerpedjiev) |
:---: |:---: |:---: |:---: |:---: |:---: |
[deniskyashif](https://github.com/deniskyashif) |[brunohadlich](https://github.com/brunohadlich) |[designeng](https://github.com/designeng) |[Microfed](https://github.com/Microfed) |[Nirajkashyap](https://github.com/Nirajkashyap) |[pkerpedjiev](https://github.com/pkerpedjiev) |
[<img alt="duffman85" src="https://avatars0.githubusercontent.com/u/15054422?v=4&s=117" width="117">](https://github.com/duffman85) |[<img alt="Xuefeng-Zhu" src="https://avatars0.githubusercontent.com/u/5875315?v=4&s=117" width="117">](https://github.com/Xuefeng-Zhu) |[<img alt="emyarod" src="https://avatars3.githubusercontent.com/u/8265238?v=4&s=117" width="117">](https://github.com/emyarod) |[<img alt="alexjoverm" src="https://avatars3.githubusercontent.com/u/5701162?v=4&s=117" width="117">](https://github.com/alexjoverm) |[<img alt="amilajack" src="https://avatars1.githubusercontent.com/u/6374832?v=4&s=117" width="117">](https://github.com/amilajack) |[<img alt="BorislavBorisov22" src="https://avatars2.githubusercontent.com/u/20156662?v=4&s=117" width="117">](https://github.com/BorislavBorisov22) |
:---: |:---: |:---: |:---: |:---: |:---: |
[duffman85](https://github.com/duffman85) |[Xuefeng-Zhu](https://github.com/Xuefeng-Zhu) |[emyarod](https://github.com/emyarod) |[alexjoverm](https://github.com/alexjoverm) |[amilajack](https://github.com/amilajack) |[BorislavBorisov22](https://github.com/BorislavBorisov22) |
[<img alt="brunob15" src="https://avatars2.githubusercontent.com/u/5839627?v=4&s=117" width="117">](https://github.com/brunob15) |[<img alt="BryanChan777" src="https://avatars0.githubusercontent.com/u/43082778?v=4&s=117" width="117">](https://github.com/BryanChan777) |[<img alt="ysharplanguage" src="https://avatars0.githubusercontent.com/u/1055314?v=4&s=117" width="117">](https://github.com/ysharplanguage) |[<img alt="jurassix" src="https://avatars3.githubusercontent.com/u/1869117?v=4&s=117" width="117">](https://github.com/jurassix) |[<img alt="fisenkodv" src="https://avatars0.githubusercontent.com/u/1039447?v=4&s=117" width="117">](https://github.com/fisenkodv) |[<img alt="contra" src="https://avatars0.githubusercontent.com/u/425716?v=4&s=117" width="117">](https://github.com/contra) |
:---: |:---: |:---: |:---: |:---: |:---: |
[brunob15](https://github.com/brunob15) |[BryanChan777](https://github.com/BryanChan777) |[ysharplanguage](https://github.com/ysharplanguage) |[jurassix](https://github.com/jurassix) |[fisenkodv](https://github.com/fisenkodv) |[contra](https://github.com/contra) |
[<img alt="liesislukas" src="https://avatars3.githubusercontent.com/u/2733862?v=4&s=117" width="117">](https://github.com/liesislukas) |[<img alt="marrcelo" src="https://avatars3.githubusercontent.com/u/18054556?v=4&s=117" width="117">](https://github.com/marrcelo) |[<img alt="wnvko" src="https://avatars3.githubusercontent.com/u/5990334?v=4&s=117" width="117">](https://github.com/wnvko) |[<img alt="millerrach" src="https://avatars2.githubusercontent.com/u/12432794?v=4&s=117" width="117">](https://github.com/millerrach) |[<img alt="xiedezhuo" src="https://avatars3.githubusercontent.com/u/39017209?v=4&s=117" width="117">](https://github.com/xiedezhuo) |[<img alt="DengYiping" src="https://avatars0.githubusercontent.com/u/12176046?v=4&s=117" width="117">](https://github.com/DengYiping) |
:---: |:---: |:---: |:---: |:---: |:---: |
[liesislukas](https://github.com/liesislukas) |[marrcelo](https://github.com/marrcelo) |[wnvko](https://github.com/wnvko) |[millerrach](https://github.com/millerrach) |[xiedezhuo](https://github.com/xiedezhuo) |[DengYiping](https://github.com/DengYiping) |
[<img alt="fanixk" src="https://avatars2.githubusercontent.com/u/921156?v=4&s=117" width="117">](https://github.com/fanixk) |[<img alt="wlx199x" src="https://avatars1.githubusercontent.com/u/6756730?v=4&s=117" width="117">](https://github.com/wlx199x) |[<img alt="shaunak1111" src="https://avatars3.githubusercontent.com/u/1323960?v=4&s=117" width="117">](https://github.com/shaunak1111) |
:---: |:---: |:---: |
[fanixk](https://github.com/fanixk) |[wlx199x](https://github.com/wlx199x) |[shaunak1111](https://github.com/shaunak1111) |
## License
The code in this repository is distributed under the terms of the MIT license.
================================================
FILE: src/combinatorics/cartesianproduct.js
================================================
(function (exports) {
'use strict';
var cartesianProduct = (function () {
var result;
function cartesianProduct(sets, index, current) {
if (index === sets.length) {
return result.push(current.slice());
}
for (var i = 0; i < sets[index].length; i += 1) {
current[index] = sets[index][i];
cartesianProduct(sets, index + 1, current);
}
}
/**
* Calculates Cartesian product of provided sets.
*
* @module combinatorics/cartesianproduct
* @public
* @param {Array} sets Array of sets.
* @return {Array} Cartesian product of provided sets.
*
* @example
* var product = require('path-to-algorithms/src/combinatorics/' +
* 'cartesianproduct').cartesianProduct;
* var result = product([[1, 2, 3], [3, 2, 1]]);
* // [ [ 1, 3 ],
* // [ 1, 2 ],
* // [ 1, 1 ],
* // [ 2, 3 ],
* // [ 2, 2 ],
* // [ 2, 1 ],
* // [ 3, 3 ],
* // [ 3, 2 ],
* // [ 3, 1 ] ]
* console.log(result);
*/
return function (sets) {
result = [];
cartesianProduct(sets, 0, []);
return result;
};
}());
exports.cartesianProduct = cartesianProduct;
}((typeof window === 'undefined') ? module.exports : window));
================================================
FILE: src/combinatorics/combinations.js
================================================
(function (exports) {
'use strict';
var combinations = (function () {
var res = [];
function combinations(arr, k, start, idx, current) {
if (idx === k) {
res.push(current.slice());
return;
}
for (var i = start; i < arr.length; i += 1) {
current[idx] = arr[i];
combinations(arr, k, i + 1, idx + 1, current);
}
}
/**
* Finds all the combinations of given array.<br><br>
* A combination is a way of selecting members from a grouping,
* such that (unlike permutations) the order of selection does not matter.
* For example given three fruits, say an apple, an orange and a pear,
* there are three combinations of two that can be drawn from this set:
* an apple and a pear; an apple and an orange; or a pear and an orange.
*
* @example
*
* var combinations = require('path-to-algorithms/src/' +
* 'combinatorics/combinations').combinations;
* var result = combinations(['apple', 'orange', 'pear'], 2);
* // [['apple', 'orange'],
* // ['apple', 'pear'],
* // ['orange', 'pear']]
* console.log(result);
*
* @module combinatorics/combinations
* @public
* @param arr {Array} Set of items.
* @param k {Number} Size of each combination.
* @return {Array} Returns all combinations.
*/
return function (arr, k) {
res = [];
combinations(arr, k, 0, 0, []);
var temp = res;
// Free the extra memory
res = null;
return temp;
};
}());
exports.combinations = combinations;
}((typeof window === 'undefined') ? module.exports : window));
================================================
FILE: src/combinatorics/permutations.js
================================================
(function (exports) {
'use strict';
var permutations = (function () {
var res;
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function permutations(arr, current) {
if (current >= arr.length) {
return res.push(arr.slice());
}
for (var i = current; i < arr.length; i += 1) {
swap(arr, i, current);
permutations(arr, current + 1);
swap(arr, i, current);
}
}
/**
* Finds all the permutations of given array.<br><br>
* Permutation relates to the act of rearranging, or permuting,
* all the members of a set into some sequence or order.
* For example there are six permutations of the set {1,2,3}, namely:
* (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), and (3,2,1).<br><br>
* Complexity: O(N*N!).
*
* @example
*
* var permutations = require('path-to-algorithms/src/' +
* 'combinatorics/permutations').permutations;
* var result = permutations(['apple', 'orange', 'pear']);
*
* // [ [ 'apple', 'orange', 'pear' ],
* // [ 'apple', 'pear', 'orange' ],
* // [ 'orange', 'apple', 'pear' ],
* // [ 'orange', 'pear', 'apple' ],
* // [ 'pear', 'orange', 'apple' ],
* // [ 'pear', 'apple', 'orange' ] ]
* console.log(result);
*
* @module combinatorics/permutations
* @public
* @param {Array} arr Array to find the permutations of.
* @returns {Array} Array containing all the permutations.
*/
return function (arr) {
res = [];
permutations(arr, 0);
var temp = res;
// Free the extra memory
res = null;
return temp;
};
}());
exports.permutations = permutations;
}((typeof window === 'undefined') ? module.exports : window));
================================================
FILE: src/combinatorics/variations-repetition.js
================================================
(function (exports) {
'use strict';
var variationsWithRepetition = (function () {
var res;
function variations(arr, k, index, current) {
if (k === index) {
return res.push(current.slice());
}
for (var i = 0; i < arr.length; i += 1) {
current[index] = arr[i];
variations(arr, k, index + 1, current);
}
}
/**
* Finds all the variations with repetition of given array.<br><br>
* Variations with repetition is the number of ways to sample k elements
* from a set of elements (which may be repeated).
*
* @example
* var variations = require('path-to-algorithms/src/combinatorics/' +
* 'variations-repetition').variationsWithRepetition;
* var result = variations(['apple', 'orange', 'pear'], 2);
*
* // [['apple', 'apple'],
* // ['apple', 'orange'],
* // ['apple', 'pear'],
* // ['orange', 'apple'],
* // ['orange', 'orange'],
* // ['orange', 'pear'],
* // ['pear', 'apple'],
* // ['pear', 'orange'],
* // ['pear', 'pear']]
* console.log(result);
*
* @module combinatorics/variations-repetition
* @public
* @param arr {Array} Set of items.
* @param k {Number} Size of each combination.
* @return {Array} Returns all combinations.
*/
return function (arr, k) {
res = [];
variations(arr, k, 0, []);
var temp = res;
res = undefined;
return temp;
};
}());
exports.variationsWithRepetition = variationsWithRepetition;
}((typeof window === 'undefined') ? module.exports : window));
================================================
FILE: src/compression/LZW/LZW.js
================================================
/**
* LZW Encoding/Decoding
*
* Lempel–Ziv–Welch (LZW) is a universal lossless data
* compression algorithm. It is an improved implementation
* of the LZ78 algorithm.
*
* @example
* var lzwModule = require('path-to-algorithms/src/compression'+
* '/LZW/LZW');
* var lzw = new lzwModule.LZW();
*
* var compressed = lzw.compress("ABCABCABCABCABCABC");
* console.log(compressed);
*
* var decompressed = lzw.decompress(compressed);
* console.log(decompressed);
*
* @module compression/LZW/LZW
*/
(function (exports) {
'use strict';
exports.LZW = function () {
this.dictionarySize = 256;
};
exports.LZW.compress = function (data) {
var i;
var dictionary = {};
var character;
var wc;
var w = '';
var result = [];
for (i = 0; i < this.dictionarySize; i = i + 1) {
dictionary[String.fromCharCode(i)] = i;
}
for (i = 0; i < data.length; i = i + 1) {
character = data.charAt(i);
wc = w + character;
if (dictionary.hasOwnProperty(wc)) {
w = wc;
} else {
result.push(dictionary[w]);
dictionary[wc] = this.dictionarySize;
this.dictionarySize = this.dictionarySize + 1;
w = String(character);
}
}
if (w !== '') {
result.push(dictionary[w]);
}
return result;
};
exports.LZW.decompress = function (compressedData) {
var i;
var dictionary = [];
var w;
var result;
var key;
var entry = '';
for (i = 0; i < this.dictionarySize; i = i + 1) {
dictionary[i] = String.fromCharCode(i);
}
w = String.fromCharCode(compressedData[0]);
result = w;
for (i = 1; i < compressedData.length; i = i + 1) {
key = compressedData[i];
if (dictionary[key]) {
entry = dictionary[key];
} else {
if (key === this.dictionarySize) {
entry = w + w.charAt(0);
} else {
return null;
}
}
result += entry;
dictionary[this.dictionarySize] = w + entry.charAt(0);
this.dictionarySize = this.dictionarySize + 1;
w = entry;
}
return result;
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/compression/burrows-wheeler/burrows-wheeler.js
================================================
(function (exports) {
'use strict';
/**
* Burrows Wheeler.
*
* This algorithm is commonly used as a step in the process of compressing data,
* it rearranges a character string into runs of similar characters making algorithms
* like move-to-front transform and run-length encoding reach higher compression
* rates. This implementation only supports characters with ascii code greater than $(36) as
* 36 is used at the process of encode and decode.
*
* @example
* const burrows = require('path-to-algorithms/src/burrows-wheeler/burrows-wheeler').burrowsWheeler;
* const s = 'ananabanana';
* const encodedStr = burrows.encode(s);
* console.log(encodedStr);
* const decodedStr = burrows.decode(encodedStr);
* console.log(decodedStr);
*
* @module compression/burrows-wheeler/burrows-wheeler
*/
exports.burrowsWheeler = function() {
}
/**
* Consumes n^2 space.
*/
exports.burrowsWheeler.encode = function(str) {
str = '$' + str;
var combinations = [];
for (let i = 0; i < str.length; i += 1) {
combinations.push(str.substring(i) + str.substring(0, i));
}
var sorted = combinations.sort();
var result = [];
for (let i = 0; i < sorted.length; i += 1) {
result.push(combinations[i][str.length - 1]);
}
return result.join('');
}
exports.burrowsWheeler.decode = function(encodedStr) {
const sortedCharSequence = encodedStr.split('').sort().join('');
const leftSide = {};
const rightSide = {};
var maxEachCharLeft = {};
var maxEachCharRight = {};
for (let i = 0; i < encodedStr.length; i += 1) {
var idLeft = sortedCharSequence[i];
if (idLeft in maxEachCharLeft) {
maxEachCharLeft[idLeft] = maxEachCharLeft[idLeft] + 1;
} else {
maxEachCharLeft[idLeft] = 1;
}
idLeft += String(maxEachCharLeft[idLeft]);
var idRight = encodedStr[i];
if (idRight in maxEachCharRight) {
maxEachCharRight[idRight] = maxEachCharRight[idRight] + 1;
} else {
maxEachCharRight[idRight] = 1;
}
idRight += String(maxEachCharRight[idRight]);
leftSide[idLeft] = {char: sortedCharSequence[i], right: idRight};
rightSide[idRight] = {char: encodedStr[i], left: idRight};
}
var result = '';
var firstChar = sortedCharSequence[0];
var searchChar = firstChar + '1';
var endChar = searchChar;
while (rightSide[leftSide[searchChar].right].left !== endChar) {
result += leftSide[searchChar].char;
searchChar = rightSide[leftSide[searchChar].right].left;
}
result += leftSide[searchChar].char;
result = result.substring(1).split('').reverse().join('');
return result;
}
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/compression/runlength/runlength.js
================================================
/**
* Run-length encoding.
* The idea of this algorithm is to remove the usless zeros and
* give us representation of string in binary which in which the
* zeros will be stripped and replaced with their count.
*/
(function (exports) {
'use strict';
var runLengthEncoding = (function () {
/**
* Converts a given string to sequence of numbers
* This takes O(n).
*/
function convertToAscii(str) {
var result = [];
var currentChar = '';
var i = 0;
for (; i < str.length; i += 1) {
currentChar = str[i].charCodeAt(0).toString(2);
currentChar = new Array(9 - currentChar.length).join('0') + currentChar;
result.push(currentChar);
}
return result.join('');
}
/**
* Encodes the binary string to run-length encoding.
* Takes O(n^2).
*/
function runLength(vector) {
var result = [];
var zeros = 0;
var zerosTemp = '';
var i = 0;
for (; i < vector.length; i += 1) {
if (vector[i] === '0') {
zeros += 1;
} else {
zerosTemp = zeros.toString(2);
result.push(new Array(zerosTemp.length).join('1'));
result.push('0' + zerosTemp);
zeros = 0;
}
}
return result.join('');
}
/**
* Accepts a string and returns it's run-length
* encoded binary representation.
* Takes O(n^2).
*/
return function (str) {
var asciiString = convertToAscii(str);
return runLength(asciiString);
};
}());
exports.runLength = runLengthEncoding;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/data-structures/avl-tree.js
================================================
/**
* AVL tree, a Binary Search Tree that satisfies the Height-Balance
* Property.
*
* @example
* var avlTree = require('path-to-algorithms/src/data-structures'+
* '/avl-tree');
* var avl = new avlTree.AVLTree();
*
* avl.insert(2000);
* avl.insert(1989);
* avl.insert(1991);
* avl.insert(2001);
* avl.insert(1966);
*
* @module data-structures/avl-tree
*/
(function (exports) {
'use strict';
/**
* Node of the tree.
*
* @public
* @constructor
* @param {Number|String} value Value of the node.
* @param {Node} left Left sibling.
* @param {Node} right Right sibling.
* @param {Node} parent Parent of the node.
* @param {Number} height Height of the node.
*/
exports.Node = function (value, left, right, parent, height) {
/**
* @member {Number|String}
*/
this.value = value;
this._left = left;
this._right = right;
this._parent = parent;
this._height = height;
};
/**
* AVL Tree.
*
* @public
* @constructor
*/
exports.AVLTree = function () {
this._root = null;
};
/**
* Calculates the height of a node based on height
* property of children.
*
* @public
* @method
* @param {Node} node Given node's height is returned.
*/
exports.AVLTree.prototype._getHeightAtNode = function (node) {
if (node._left !== null && node._right !== null){
var height = Math.max(node._left._height, node._right._height);
height += 1;
return height;
} else if (node._left !== null){
return node._left._height + 1;
} else if (node._right !== null){
return node._right._height + 1;
} else {
return 1;
}
};
/**
* Checks if a given node has an imbalance.
*
* @public
* @method
* @param {Node} node Given node's children are checked for
* imbalance.
*/
exports.AVLTree.prototype._isBalancedAtNode = function (node) {
if (node._left !== null && node._right !== null){
return (Math.abs(node._left._height - node._right._height) <= 1);
}
if (node._right !== null && node._left === null){
return node._right._height < 2;
}
if (node._left !== null && node._right === null){
return node._left._height < 2;
}
return true;
};
/**
* Gets the nodes to be restructured during an AVL restructure
* after a remove/delete takes place.
*
* @public
* @method
* @param {Array} traveledNodes Array of previously traveled nodes
* that are used to help determine the nodes to be restructured.
*/
exports.AVLTree.prototype._getNodesToRestructureRemove = function (traveledNodes) {
// z is last traveled node - imbalance found at z
var zIndex = traveledNodes.length;
zIndex -= 1;
var z = traveledNodes[zIndex];
// y should be child of z with larger height
// (cannot be ancestor of removed node)
var y;
if ((z._left !== null && z._right !== null) || (z._left !== null && z._right === null)){
y = z._left;
} else if (z._right !== null && z._left === null){
y = z._right;
}
// x should be tallest child of y.
// If children same height, x should be child of y
// that has same orientation as z to y.
var x;
if (y._left !== null && y._right !== null){
if (y._left._height > y._right._height){
x = y._left;
} else if (y._left._height < y._right._height){
x = y._right;
} else if (y._left._height === y._right._height){
x = (z._left === y) ? y._left : y._right;
}
} else if (y._left !== null && y._right === null){
x = y._left;
} else if (y._right !== null && y._left === null){
x = y._right;
}
return [x, y, z];
};
/**
* Gets the nodes to be restructured during an AVL restructure
* after an insert takes place.
*
* @public
* @method
* @param {Array} traveledNodes Array of previously traveled nodes
* that are used to help determine the nodes to be restructured.
*/
exports.AVLTree.prototype._getNodesToRestructureInsert = function (traveledNodes) {
// z is last traveled node - imbalance found at z
var zIndex = traveledNodes.length;
zIndex -= 1;
var z = traveledNodes[zIndex];
// y should be child of z with larger height
// (must be ancestor of inserted node)
// therefore, last traveled node is correct.
var yIndex = traveledNodes.length;
yIndex -= 2;
var y = traveledNodes[yIndex];
// x should be tallest child of y.
// If children same height, x should be ancestor
// of inserted node (in traveled path).
var x;
if (y._left !== null && y._right !== null){
if (y._left._height > y._right._height){
x = y._left;
} else if (y._left._height < y._right._height){
x = y._right;
} else if (y._left._height === y._right._height){
var xIndex = traveledNodes.length;
xIndex -= 3;
x = traveledNodes[xIndex];
}
} else if (y._left !== null && y._right === null){
x = y._left;
} else if (y._right !== null && y._left === null){
x = y._right;
}
return [x, y, z];
};
/**
* Maintains the height balance property by
* walking to root and checking for invalid height
* differences between children and restructuring
* appropriately.
*
* @public
* @method
* @param {Node} node Started node.
* @param {Boolean} isRemove Represents if method was called after remove.
*/
exports.AVLTree.prototype._maintainHeightBalanceProperty = function (node, isRemove) {
var current = node;
var traveledNodes = [];
while (current !== null){
traveledNodes.push(current);
current._height = this._getHeightAtNode(current);
if (!this._isBalancedAtNode(current)){
var nodesToBeRestructured = (isRemove)
? this._getNodesToRestructureRemove(traveledNodes)
: this._getNodesToRestructureInsert(traveledNodes);
this._restructure(nodesToBeRestructured);
}
current = current._parent;
}
};
/**
* Identifies the pattern of given nodes, then calls
* the appropriate pattern rotator.
*
* @public
* @method
* @param {Array} nodesToBeRestructured
* array of nodes, in format, [x, y, z], to be restructured
*/
exports.AVLTree.prototype._restructure = function (nodesToBeRestructured) {
var x = nodesToBeRestructured[0];
var y = nodesToBeRestructured[1];
var z = nodesToBeRestructured[2];
//Determine Rotation Pattern
if (z._right === y && y._right === x){
this._rightRight(x, y, z);
} else if (z._left === y && y._left === x){
this._leftLeft(x, y, z);
} else if (z._right === y && y._left === x){
this._rightLeft(x, y, z);
} else if (z._left === y && y._right === x){
this._leftRight(x, y, z);
}
};
/**
* Rotates the given nodes from a right right pattern
* to a parent, with 2 children.
*
* @public
* @method
* @param {Node} x node with lowest height to be restructured.
* @param {Node} y parent of x parameter.
* @param {Node} z grandparent of x, largest height.
*/
exports.AVLTree.prototype._rightRight = function (x, y, z) {
/*
z
y => y
x z x
*/
// pass z parent to y and move y's left to z's right
if (z._parent !== null){
var orientation = (z._parent._left === z) ? '_left' : '_right';
z._parent[orientation] = y;
y._parent = z._parent;
} else {
this._root = y;
y._parent = null;
}
// z adopts y's left.
z._right = y._left;
if (z._right !== null){
z._right._parent = z;
}
// y adopts z
y._left = z;
z._parent = y;
// Correct each nodes height - order matters, children first
x._height = this._getHeightAtNode(x);
z._height = this._getHeightAtNode(z);
y._height = this._getHeightAtNode(y);
};
/**
* Rotates the given nodes from a left left pattern
* to a parent, with 2 children.
*
* @public
* @method
* @param {Node} x node with lowest height to be restructured.
* @param {Node} y parent of x parameter.
* @param {Node} z grandparent of x, largest height.
*/
exports.AVLTree.prototype._leftLeft = function (x, y, z) {
/*
z
y => y
x x z
*/
//pass z parent to y and move y's right to z's left
if (z._parent !== null){
var orientation = (z._parent._left === z) ? '_left' : '_right';
z._parent[orientation] = y;
y._parent = z._parent;
} else {
this._root = y;
y._parent = null;
}
z._left = y._right;
if (z._left !== null) {
z._left._parent = z;
}
//fix y right child
y._right = z;
z._parent = y;
// Correct each nodes height - order matters, children first
x._height = this._getHeightAtNode(x);
z._height = this._getHeightAtNode(z);
y._height = this._getHeightAtNode(y);
};
/**
* Rotates the given nodes from a right left pattern
* to a parent, with 2 children.
*
* @public
* @method
* @param {Node} x node with lowest height to be restructured.
* @param {Node} y parent of x parameter.
* @param {Node} z grandparent of x, largest height.
*/
exports.AVLTree.prototype._rightLeft = function (x, y, z) {
/*
z
y => x
x z y
*/
//pass z parent to x
if (z._parent !== null){
var orientation = (z._parent._left === z) ? '_left' : '_right';
z._parent[orientation] = x;
x._parent = z._parent;
} else {
this._root = x;
x._parent = null;
}
// Adoptions
z._right = x._left;
if (z._right !== null){
z._right._parent = z;
}
y._left = x._right;
if (y._left !== null){
y._left._parent = y;
}
// Point to new children (x new parent)
x._left = z;
x._right = y;
x._left._parent = x;
x._right._parent = x;
// Correct each nodes height - order matters, children first
y._height = this._getHeightAtNode(y);
z._height = this._getHeightAtNode(z);
x._height = this._getHeightAtNode(x);
};
/**
* Rotates the given nodes from a left right pattern
* to a parent, with 2 children.
*
* @public
* @method
* @param {Node} x node with lowest height to be restructured.
* @param {Node} y parent of x parameter.
* @param {Node} z grandparent of x, largest height.
*/
exports.AVLTree.prototype._leftRight = function (x, y, z) {
/*
z
y => x
x y z
*/
//pass z parent to x
if (z._parent !== null){
var orientation = (z._parent._left === z) ? '_left' : '_right';
z._parent[orientation] = x;
x._parent = z._parent;
} else {
this._root = x;
x._parent = null;
}
// Adoptions
z._left = x._right;
if (z._left !== null){
z._left._parent = z;
}
y._right = x._left;
if (y._right !== null){
y._right._parent = y;
}
// Point to new children (x new parent)
x._right = z;
x._left = y;
x._left._parent = x;
x._right._parent = x;
// Correct each nodes height - order matters, children first
y._height = this._getHeightAtNode(y);
z._height = this._getHeightAtNode(z);
x._height = this._getHeightAtNode(x);
};
/**
* Inserts a node into the AVL Tree.<br><br>
* Time complexity: O(log N) in the average case
* and O(N) in the worst case.
*
* @public
* @method
* @param {Number|String} value Node value.
* @param {Node} current Current node.
*/
exports.AVLTree.prototype.insert = function (value, current) {
if (this._root === null) {
this._root = new exports.Node(value, null, null, null, 1);
this._maintainHeightBalanceProperty(this._root);
return;
}
var insertKey;
current = current || this._root;
if (current.value > value) {
insertKey = '_left';
} else {
insertKey = '_right';
}
if (!current[insertKey]) {
current[insertKey] = new exports.Node(value, null, null, current);
this._maintainHeightBalanceProperty(current[insertKey], false);
} else {
this.insert(value, current[insertKey]);
}
};
/**
* In-order traversal from the given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.AVLTree.prototype._inorder = function (current, callback) {
if (!current) {
return;
}
this._inorder(current._left, callback);
if (typeof callback === 'function') {
callback(current);
}
this._inorder(current._right, callback);
};
/**
* In-order traversal of the whole AVL tree.
*
* @public
* @method
* @param {Function} callback Callback which will be
* called for each traversed node.
*/
exports.AVLTree.prototype.inorder = function (callback) {
return this._inorder(this._root, callback);
};
/**
* Post-order traversal from given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which will
* be called for each traversed node
*/
exports.AVLTree.prototype._postorder = function (current, callback) {
if (!current) {
return;
}
if (typeof callback === 'function') {
callback(current);
}
this._postorder(current._left, callback);
this._postorder(current._right, callback);
};
/**
* Post-order traversal of the whole tree.
*
* @public
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.AVLTree.prototype.postorder = function (callback) {
return this._postorder(this._root, callback);
};
/**
* Pre-order traversal of the tree from given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.AVLTree.prototype._preorder = function (current, callback) {
if (!current) {
return;
}
if (typeof callback === 'function') {
callback(current);
}
this._preorder(current._left, callback);
this._preorder(current._right, callback);
};
/**
* Pre-order preorder traversal of the whole tree.
*
* @public
* @param {Function} callback Callback which will
* be called for each traversed node.
*/
exports.AVLTree.prototype.preorder = function (callback) {
return this._preorder(this._root, callback);
};
/**
* Finds a node by it's value.<br><br>
* Average time complexity: O(log N).
*
* @public
* @param {Number|String} value of the node which should be found.
*/
exports.AVLTree.prototype.find = function (value) {
return this._find(value, this._root);
};
/**
* Finds a node by it's value in a given sub-tree.
* Average time complexity: O(log N).
*
* @private
* @param {Number|String} value of the node which should be found.
* @param {Node} current node to be checked.
*/
exports.AVLTree.prototype._find = function (value, current) {
if (!current) {
return null;
}
if (current.value === value) {
return current;
}
if (current.value > value) {
return this._find(value, current._left);
}
if (current.value < value) {
return this._find(value, current._right);
}
};
/**
* Replaces given child with new one, for given parent.
*
* @private
* @param {Node} parent Parent node.
* @param {Node} oldChild Child to be replaced.
* @param {Node} newChild Child replacement.
*/
exports.AVLTree.prototype._replaceChild = function (parent, oldChild, newChild) {
if (parent === null) {
this._root = newChild;
if (this._root !== null){
this._root._parent = null;
}
} else {
if (parent._left === oldChild) {
parent._left = newChild;
} else {
parent._right = newChild;
}
if (newChild) {
newChild._parent = parent;
}
}
};
/**
* Removes node from the tree. <br><br>
* Average runtime complexity: O(log N).
*
* @public
* @param {Number|String} value of node to be removed
* @returns {Boolean} True/false depending
* on whether the given node is removed.
*/
exports.AVLTree.prototype.remove = function (value) {
var node = this.find(value);
if (!node) {
return false;
}
if (node._left && node._right) {
var min = this._findMin(node._right);
var temp = node.value;
node.value = min.value;
min.value = temp;
return this.remove(temp);
} else {
if (node._left) {
this._replaceChild(node._parent, node, node._left);
this._maintainHeightBalanceProperty(node._left, true);
} else if (node._right) {
this._replaceChild(node._parent, node, node._right);
this._maintainHeightBalanceProperty(node._right, true);
} else {
this._replaceChild(node._parent, node, null);
this._maintainHeightBalanceProperty(node._parent, true);
}
return true;
}
};
/**
* Finds the node with minimum value in given sub-tree.
*
* @private
* @param {Node} node Root of the sub-tree.
* @param {Number|String} current Current minimum value of the sub-tree.
* @returns {Node} Node with the minimum value in the sub-tree.
*/
exports.AVLTree.prototype._findMin = function (node, current) {
current = current || { value: Infinity };
if (!node) {
return current;
}
if (current.value > node.value) {
current = node;
}
return this._findMin(node._left, current);
};
/**
* Finds the node with maximum value in given sub-tree.
*
* @private
* @param {Node} node Root of the sub-tree.
* @param {Number|String} current Current maximum value of the sub-tree.
* @returns {Node} Node with the maximum value in the sub-tree.
*/
exports.AVLTree.prototype._findMax = function (node, current) {
current = current || { value: -Infinity };
if (!node) {
return current;
}
if (current.value < node.value) {
current = node;
}
return this._findMax(node._right, current);
};
/**
* Finds the node with minimum value in the whole tree.
*
* @public
* @returns {Node} The minimum node of the tree.
*/
exports.AVLTree.prototype.findMin = function () {
return this._findMin(this._root);
};
/**
* Finds the node with maximum value in the whole tree.
*
* @public
* @returns {Node} The maximum node of the tree.
*
*/
exports.AVLTree.prototype.findMax = function () {
return this._findMax(this._root);
};
exports.AVLTree.prototype._isBalanced = function (current) {
if (!current) {
return true;
}
return this._isBalanced(current._left) &&
this._isBalanced(current._right) &&
Math.abs(this._getHeight(current._left) -
this._getHeight(current._right)) <= 1;
};
/**
* Returns whether the AVL Tree is balanced.
*
* @public
* @returns {Boolean} Whether the tree is balanced or not.
*/
exports.AVLTree.prototype.isBalanced = function () {
return this._isBalanced(this._root);
};
/**
* Finds the diameter of the AVL tree.
*
* @public
* @returns {Number} The longest path in the AVL Tree.
*/
exports.AVLTree.prototype.getDiameter = function () {
var getDiameter = function (root) {
if (!root) {
return 0;
}
var leftHeight = this._getHeight(root._left);
var rightHeight = this._getHeight(root._right);
var path = leftHeight + rightHeight + 1;
return Math.max(path, getDiameter(root._left), getDiameter(root._right));
}.bind(this);
return getDiameter(this._root);
};
/**
* Returns the height of the tree.
*
* @public
* @returns {Number} The height of the tree.
*/
exports.AVLTree.prototype.getTreeHeight = function () {
return this._getHeight(this._root);
};
exports.AVLTree.prototype._getHeight = function (node) {
if (!node) {
return 0;
}
return 1 + Math.max(this._getHeight(node._left),
this._getHeight(node._right));
};
/**
* Finds the lowest common ancestor of two nodes.
*
* @public
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.AVLTree.prototype.lowestCommonAncestor = function (firstNode, secondNode) {
return this._lowestCommonAncestor(firstNode, secondNode, this._root);
};
exports.AVLTree.prototype._lowestCommonAncestor = function (firstNode, secondNode, current) {
var firstNodeInLeft = this._existsInSubtree(firstNode, current._left);
var secondNodeInLeft = this._existsInSubtree(secondNode, current._left);
var firstNodeInRight = this._existsInSubtree(firstNode, current._right);
var secondNodeInRight = this._existsInSubtree(secondNode, current._right);
if ((firstNodeInLeft && secondNodeInRight) ||
(firstNodeInRight && secondNodeInLeft)) {
return current;
}
if (secondNodeInLeft && firstNodeInLeft) {
return this._lowestCommonAncestor(firstNode, secondNode, current._left);
}
if (secondNodeInRight && secondNodeInLeft) {
return this._lowestCommonAncestor(firstNode, secondNode, current._right);
}
return null;
};
exports.AVLTree.prototype._existsInSubtree = function (node, root) {
if (!root) {
return false;
}
if (node === root.value) {
return true;
}
return this._existsInSubtree(node, root._left) ||
this._existsInSubtree(node, root._right);
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/binary-search-tree.js
================================================
/**
* Binary search tree.
*
* @example
* var BST = require('path-to-algorithms/src/data-structures'+
* '/binary-search-tree');
* var bst = new BST.BinaryTree();
*
* bst.insert(2000);
* bst.insert(1989);
* bst.insert(1991);
* bst.insert(2001);
* bst.insert(1966);
*
* var node = bst.find(1989);
* console.log(node.value); // 1989
*
* var minNode = bst.findMin();
* console.log(minNode.value); // 1966
*
* var maxNode = bst.findMax();
* console.log(maxNode.value); //2001
*
* @module data-structures/binary-search-tree
*/
(function (exports) {
'use strict';
/**
* Node of the tree.
*
* @public
* @constructor
* @param {Number|String} value Value of the node.
* @param {Node} left Left sibling.
* @param {Node} right Right sibling.
* @param {Node} parent Parent of the node.
*/
exports.Node = function (value, left, right, parent) {
/**
* @member {Number|String}
*/
this.value = value;
this._left = left;
this._right = right;
this._parent = parent;
};
/**
* Binary tree.
*
* @public
* @constructor
*/
exports.BinaryTree = function () {
this._root = null;
};
/**
* Inserts a node into the binary search tree.<br><br>
* Time complexity: O(log N) in the average case
* and O(N) in the worst case.
*
* @public
* @method
* @param {Number|String} value Node value.
* @param {Node} current Current node.
*/
exports.BinaryTree.prototype.insert = function (value, current) {
if (this._root === null) {
this._root = new exports.Node(value, null, null, null);
return;
}
var insertKey;
current = current || this._root;
if (current.value > value) {
insertKey = '_left';
} else {
insertKey = '_right';
}
if (!current[insertKey]) {
current[insertKey] = new exports.Node(value, null, null, current);
} else {
this.insert(value, current[insertKey]);
}
};
/**
* In-order traversal from the given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.BinaryTree.prototype._inorder = function (current, callback) {
if (!current) {
return;
}
this._inorder(current._left, callback);
if (typeof callback === 'function') {
callback(current);
}
this._inorder(current._right, callback);
};
/**
* In-order traversal of the whole binary search tree.
*
* @public
* @method
* @param {Function} callback Callback which will be
* called for each traversed node.
*/
exports.BinaryTree.prototype.inorder = function (callback) {
return this._inorder(this._root, callback);
};
/**
* Post-order traversal from given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which will
* be called for each traversed node
*/
exports.BinaryTree.prototype._postorder = function (current, callback) {
if (!current) {
return;
}
this._postorder(current._left, callback);
this._postorder(current._right, callback);
if (typeof callback === 'function') {
callback(current);
}
};
/**
* Post-order traversal of the whole tree.
*
* @public
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.BinaryTree.prototype.postorder = function (callback) {
return this._postorder(this._root, callback);
};
/**
* Pre-order traversal of the tree from given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.BinaryTree.prototype._preorder = function (current, callback) {
if (!current) {
return;
}
if (typeof callback === 'function') {
callback(current);
}
this._preorder(current._left, callback);
this._preorder(current._right, callback);
};
/**
* Pre-order preorder traversal of the whole tree.
*
* @public
* @param {Function} callback Callback which will
* be called for each traversed node.
*/
exports.BinaryTree.prototype.preorder = function (callback) {
return this._preorder(this._root, callback);
};
/**
* Finds a node by it's value.<br><br>
* Average time complexity: O(log N).
*
* @public
* @param {Number|String} value of the node which should be found.
*/
exports.BinaryTree.prototype.find = function (value) {
return this._find(value, this._root);
};
/**
* Finds a node by it's value in a given sub-tree.
* Average time complexity: O(log N).
*
* @private
* @param {Number|String} value of the node which should be found.
* @param {Node} current node to be checked.
*/
exports.BinaryTree.prototype._find = function (value, current) {
if (!current) {
return null;
}
if (current.value === value) {
return current;
}
if (current.value > value) {
return this._find(value, current._left);
}
if (current.value < value) {
return this._find(value, current._right);
}
};
/**
* Replaces given child with new one, for given parent.
*
* @private
* @param {Node} parent Parent node.
* @param {Node} oldChild Child to be replaced.
* @param {Node} newChild Child replacement.
*/
exports.BinaryTree.prototype._replaceChild = function (parent, oldChild, newChild) {
if (!parent) {
this._root = newChild;
if (this._root !== null){
this._root._parent = null;
}
} else {
if (parent._left === oldChild) {
parent._left = newChild;
} else {
parent._right = newChild;
}
if (newChild) {
newChild._parent = parent;
}
}
};
/**
* Removes node from the tree. <br><br>
* Average runtime complexity: O(log N).
*
* @public
* @param {Node} node to be removed
* @returns {Boolean} True/false depending
* on whether the given node is removed.
*/
exports.BinaryTree.prototype.remove = function (node) {
if (!node) {
return false;
}
if (node._left && node._right) {
var min = this._findMin(node._right);
var temp = node.value;
node.value = min.value;
min.value = temp;
return this.remove(min);
} else {
if (node._left) {
this._replaceChild(node._parent, node, node._left);
} else if (node._right) {
this._replaceChild(node._parent, node, node._right);
} else {
this._replaceChild(node._parent, node, null);
}
return true;
}
};
/**
* Finds the node with minimum value in given sub-tree.
*
* @private
* @param {Node} node Root of the sub-tree.
* @param {Number|String} current Current minimum value of the sub-tree.
* @returns {Node} Node with the minimum value in the sub-tree.
*/
exports.BinaryTree.prototype._findMin = function (node, current) {
current = current || { value: Infinity };
if (!node) {
return current;
}
if (current.value > node.value) {
current = node;
}
return this._findMin(node._left, current);
};
/**
* Finds the node with maximum value in given sub-tree.
*
* @private
* @param {Node} node Root of the sub-tree.
* @param {Number|String} current Current maximum value of the sub-tree.
* @returns {Node} Node with the maximum value in the sub-tree.
*/
exports.BinaryTree.prototype._findMax = function (node, current) {
current = current || { value: -Infinity };
if (!node) {
return current;
}
if (current.value < node.value) {
current = node;
}
return this._findMax(node._right, current);
};
/**
* Finds the node with minimum value in the whole tree.
*
* @public
* @returns {Node} The minimum node of the tree.
*/
exports.BinaryTree.prototype.findMin = function () {
return this._findMin(this._root);
};
/**
* Finds the node with maximum value in the whole tree.
*
* @public
* @returns {Node} The maximum node of the tree.
*
*/
exports.BinaryTree.prototype.findMax = function () {
return this._findMax(this._root);
};
/**
* Checks if a given node is balanced.
*
* @private
* @param {Node} current Node to have balance checked.
* @returns {Boolean} Boolean of whether or not provided node is balanced.
*/
exports.BinaryTree.prototype._isBalanced = function (current) {
if (!current) {
return true;
}
return this._isBalanced(current._left) &&
this._isBalanced(current._right) &&
Math.abs(this._getHeight(current._left) -
this._getHeight(current._right)) <= 1;
};
/**
* Returns whether the BST is balanced.
*
* @public
* @returns {Boolean} Whether the tree is balanced or not.
*/
exports.BinaryTree.prototype.isBalanced = function () {
return this._isBalanced(this._root);
};
/**
* Finds the diameter of the binary tree.
*
* @public
* @returns {Number} The longest path in the BST.
*/
exports.BinaryTree.prototype.getDiameter = function () {
var getDiameter = function (root) {
if (!root) {
return 0;
}
var leftHeight = this._getHeight(root._left);
var rightHeight = this._getHeight(root._right);
var path = leftHeight + rightHeight + 1;
return Math.max(path, getDiameter(root._left), getDiameter(root._right));
}.bind(this);
return getDiameter(this._root);
};
/**
* Returns the height of the tree.
*
* @public
* @returns {Number} The height of the tree.
*/
exports.BinaryTree.prototype.getHeight = function () {
return this._getHeight(this._root);
};
/**
* Recursive worker function for getHeight()
*
* @private
* @param {Node} node Node at current recursive frame.
* @returns {Number} Height of the Node in the parameter.
*/
exports.BinaryTree.prototype._getHeight = function (node) {
if (!node) {
return 0;
}
return 1 + Math.max(this._getHeight(node._left),
this._getHeight(node._right));
};
/**
* Finds the lowest common ancestor of two nodes.
*
* @public
* @param {Node} firstNode First node to be considered when checking
* for ancestor.
* @param {Node} secondNode Second node to be considered when checking
* for ancestor.
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.BinaryTree.prototype.lowestCommonAncestor = function (firstNode, secondNode) {
return this._lowestCommonAncestor(firstNode, secondNode, this._root);
};
/**
* Obtains the lowest common ancestor for the given nodes.
*
* @private
* @param {Node} firstNode First node to be considered when checking
* for ancestor.
* @param {Node} secondNode Second node to be considered when checking
* for ancestor.
* @param {Node} current Current node.
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.BinaryTree.prototype._lowestCommonAncestor = function (firstNode, secondNode, current) {
var firstNodeInLeft = this._existsInSubtree(firstNode, current._left);
var secondNodeInLeft = this._existsInSubtree(secondNode, current._left);
var firstNodeInRight = this._existsInSubtree(firstNode, current._right);
var secondNodeInRight = this._existsInSubtree(secondNode, current._right);
if ((firstNodeInLeft && secondNodeInRight) ||
(firstNodeInRight && secondNodeInLeft)) {
return current;
}
if (secondNodeInLeft && firstNodeInLeft) {
return this._lowestCommonAncestor(firstNode, secondNode, current._left);
}
if (secondNodeInRight && secondNodeInLeft) {
return this._lowestCommonAncestor(firstNode, secondNode, current._right);
}
return null;
};
/**
* Checks if a given node exists in a subtree.
*
* @private
* @param {Node} node Node to check for.
* @param {Node} root Root node of a given subtree.
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.BinaryTree.prototype._existsInSubtree = function (node, root) {
if (!root) {
return false;
}
if (node.value === root.value) {
return true;
}
return this._existsInSubtree(node, root._left) ||
this._existsInSubtree(node, root._right);
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/bloomfilter.js
================================================
/**
* Bloomfilter and a bitmap.
* Probablistic data structure useful for deduplication
*
* @example
* // create a bloom filter with capacity of 1024 and 0.01 error rat
* var bloomfilter = new Bloomfilter(1024, 0.01);
* bloomfilter.set('hello');
* bloomfilter.get('hello') === true;
* bloomfilter.get('world') === false;
* @module data-structures/bloomfilter
*/
(function(exports) {
'use strict';
function randomUint32() {
return Math.floor(Math.random() * Math.pow(2, 32));
}
/**
* Calculate a 32 bit FNV-1a hash
* Found here: https://gist.github.com/vaiorabbit/5657561
* Ref.: http://isthe.com/chongo/tech/comp/fnv/
*
* @param {string} str the input value
* @param {boolean} [asString=false] set to true to return the hash value as
* 8-digit hex string instead of an integer
* @param {integer} [seed] optionally pass the hash of the previous chunk
* @returns {integer | string}
*/
function hashFnv32a(str, asString, seed) {
/*jshint bitwise:false */
var i;
var l;
var hval = seed === undefined ? 0x811c9dc5 : seed;
for (i = 0, l = str.length; i < l; i = i + 1) {
hval ^= str.charCodeAt(i);
hval +=
(hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
if (asString) {
// Convert to 8 digit hex string
return ('0000000' + (hval >>> 0).toString(16)).substr(-8);
}
return hval >>> 0;
}
// Make a hash function
function mkHashFun(seed, limit) {
return function(value) {
return hashFnv32a(value, false, seed) % limit;
};
}
/**
* Create a bitmap with a given size
* Bit map is not resizeable
* @public
* @constructor
* @param {Number} size the size of the bitmap
*/
exports.Bitmap = function(size) {
size = size || 1024;
if (size < 0) {
throw new Error('The size cannot be negative');
}
this.size = size;
this.intSize = Math.ceil(size / 32); // number of underlying integers
// Create a 0 initialized array
this.intArray = Array.from({ length: this.intSize }, function() {
return 0;
});
};
/**
* Get the size of the bit map
* @public
* @return {Number} size of the bit map
*/
exports.Bitmap.prototype.getSize = function() {
return this.size;
};
/**
* Get if a bit is set at a particular index
* @public
* @return {Boolean} true or false value of the bit
*/
exports.Bitmap.prototype.exists = function(index) {
// Necessary boundary check
if (index < 0 || index > this.size) {
throw new Error('Index out of bound')
}
// Calculate the offset within the int
var intOffset = index % 32;
var arrayOffset = Math.floor(index / 32); // the offset for the array
var mask = 1 << intOffset;
return (mask & this.intArray[arrayOffset]) !== 0;
};
/**
* Get the bit at a particular index
* @public
* @return {Number} true or false value of the bit
*/
exports.Bitmap.prototype.get = function(index) {
// Necessary boundary check
if (index < 0 || index > this.size) {
throw new Error('Index out of bound')
}
// Calculate the offset within the int
var intOffset = index % 32;
var arrayOffset = Math.floor(index / 32); // the offset for the array
var mask = 1 << intOffset;
if ((mask & this.intArray[arrayOffset]) !== 0) {
return 1;
} else {
return 0;
}
};
/**
* Set the bit at a particular index
* @public
* @param {Number} index the index to set
* @param {Boolean} value the value that is necessary
*/
exports.Bitmap.prototype.set = function(index, value) {
// necessary boundary check
if (index < 0 || index > this.size) {
throw new Error('Index out of bound')
}
var intOffset = index % 32; //calculate the offset within the int
var arrayOffset = Math.floor(index / 32); // the offset for the array
var mask = 1 << intOffset;
// Check trutyness
if (value) {
this.intArray[arrayOffset] |= mask; // or operation
} else {
this.intArray[arrayOffset] &= ~mask; // and opertation to set 0
}
};
/**
* Construct a bloom filter by given the capacity and the error rate, default error rate is 0.001
* @public
* @constructor
* @param {Number} capacity the maximum capacity to maintain the given error rate
* @param {Number} errorRate the error rate expected under maximum capacity
*/
exports.Bloomfilter = function(capacity, errorRate) {
errorRate = errorRate || 0.001; // default error rate
if (errorRate > 1 || errorRate < 0) {
throw new Error('The error rate range is outside of bound');
}
if (capacity < 0) {
throw new Error('The capacity cannot be negative');
}
this.capacity = capacity;
this.errorRate = errorRate;
// Calculate the optimal size of the bitmap
var numBit = Math.ceil(
(capacity * Math.log(1.0 / errorRate)) / Math.pow(Math.log(2), 2)
);
// Calculate the optimal number of hash functions
this.numHashFunction = Math.ceil(Math.log(2), numBit / capacity);
// Create a bitmap
this.bitmap = new exports.Bitmap(numBit);
// Generate an array of hash functions
this.hashFunctions = Array.from(
{ length: this.numHashFunction },
function() {
return mkHashFun(randomUint32(), numBit);
}.bind(this)
);
};
/**
* To check if an item is in the filter. If it is in, it will return true,
* if it is not in the filter, highly likely it will return false, but guaranteed
* @param {Number | String} value the value that we are trying to check in the filter
*/
exports.Bloomfilter.prototype.get = function(value) {
value = String(value); // make it string
var hashes = this.hashFunctions.map(function(hashFct) {
return hashFct(value);
});
// if one of the bits is not set
for (var i = 0; i < hashes.length; i = i + 1) {
if (this.bitmap.exists(hashes[i]) === false) {
return false;
}
}
return true;
};
/**
* To set(put) an item in the bloom filter
* @public
* @param {Number | String} value the value that is been set in the filter
*/
exports.Bloomfilter.prototype.set = function(value) {
value = String(value); // make it string
var hashes = this.hashFunctions.map(function(hashFct) {
return hashFct(value);
});
// Set all the corresponding bits
for (var i = 0; i < hashes.length; i = i + 1) {
this.bitmap.set(hashes[i], true);
}
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/edge.js
================================================
(function (exports) {
'use strict';
/**
* Graph edge.
*
* @constructor
* @public
* @param {Vertex} e Vertex which this edge connects.
* @param {Vertex} v Vertex which this edge connects.
* @param {Number} distance Weight of the edge.
* @module data-structures/edge
*/
exports.Edge = function (e, v, distance) {
this.from = e;
this.to = v;
this.distance = distance;
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/hash-table.js
================================================
/**
* Hash Table
*
* An associative array, that can map keys
* (strings and numbers) to values in O(1).
*
* @example
* var hash = require('path-to-algorithms/src/data-structures'+
* '/hash-table');
* var hashTable = new hash.Hashtable();
*
* hashTable.put(10, 'value');
* hashTable.put('key', 10);
*
* console.log(hashTable.get(10)); // 'value'
* console.log(hashTable.get('key')); // 10
*
* hashTable.remove(10);
* hashTable.remove('key');
*
* console.log(hashTable.get(10)); // undefined
* console.log(hashTable.get('key')); // undefined
*
* @module data-structures/hash-table
*/
(function (exports) {
'use strict';
/**
* Constructs a Node to store data and next/prev nodes in Hash table.
*
* @public
* @constructor
* @param {Number|String} key Key of the node.
* @param {Number|String} data Data to be stored in hash table.
*/
exports.Node = function (key, data) {
this.key = key;
this.data = data;
this.next = undefined;
this.prev = undefined;
};
/**
* Construct a Hash table..
*
* @public
* @constructor
*/
exports.Hashtable = function () {
this.buckets = [];
// The higher the bucket count; less likely for collisions.
this.maxBucketCount = 100;
};
/**
* Simple non-crypto hash used to hash keys, which determines
* which bucket the value will be placed in.
* A javascript implementation of Java's 32bitint hash.
*
* @public
* @method
* @param {Number|String} val Key to be hashed.
*/
exports.Hashtable.prototype.hashCode = function (val) {
var i;
var hashCode = 0;
var character;
// If value to be hashed is already an integer, return it.
if (val.length === 0 || val.length === undefined) {
return val;
}
for (i = 0; i < val.length; i += 1) {
character = val.charCodeAt(i);
/*jshint -W016 */
hashCode = ((hashCode << 5) - hashCode) + character;
hashCode = hashCode & hashCode;
/*jshint -W016 */
}
return hashCode;
};
/**
* Puts data into the table based on hashed key value.
*
* @public
* @method
* @param {Number|String} key Key for data.
* @param {Number|String} data Data to be stored in table.
*/
exports.Hashtable.prototype.put = function (key, data, hashCode) {
/*
Make collision testing easy with optional hashCode parameter.
That should not be used! Only by spec/tests.
*/
if (hashCode === undefined) {
// Typical use
hashCode = this.hashCode(key);
} else if (hashCode.length > 0) {
// Testing/Spec - String hash passed, convert to int based hash.
hashCode = this.hashCode(hashCode);
}
// Adjust hash to fit within buckets.
hashCode = hashCode % this.maxBucketCount;
var newNode = new exports.Node(key, data);
// No element exists at hash/index for given key -> put in table.
if (this.buckets[hashCode] === undefined) {
this.buckets[hashCode] = newNode;
return;
}
// Element exists at hash/index for given key, but, same key -> overwrite.
if (this.buckets[hashCode].key === key) {
this.buckets[hashCode].data = data;
return;
}
/*
Item exists at hash/index for key, but different key.
Handle collision.
*/
var first = this.buckets[hashCode];
while (first.next !== undefined) {
first = first.next;
}
first.next = newNode;
newNode.prev = first;
};
/**
* Get's data from the table based on key.
*
* @public
* @method
* @param {Number|String} key Key for data to be retrieved.
*/
exports.Hashtable.prototype.get = function (key, hashCode) {
/*
Make collision testing easy with optional hashCode parameter.
That should not be used! Only by spec/tests.
*/
if (hashCode === undefined) {
// Typical use
hashCode = this.hashCode(key);
} else if (hashCode.length > 0) {
// Testing/Spec - String hash passed, convert to int based hash.
hashCode = this.hashCode(hashCode);
}
hashCode = hashCode % this.maxBucketCount;
if (this.buckets[hashCode] === undefined) {
return undefined;
} else if (
this.buckets[hashCode].next === undefined &&
this.buckets[hashCode].key === key
) {
return this.buckets[hashCode].data;
} else {
var first = this.buckets[hashCode];
while (
first !== undefined &&
first.next !== undefined &&
first.key !== key
) {
first = first.next;
}
if (first.key === key) {
return first.data;
} else {
return undefined;
}
}
};
/**
* Removes data from the table based on key.
*
* @public
* @method
* @param {Number|String} key Key of the data to be removed.
*/
exports.Hashtable.prototype.remove = function (key, hashCode) {
/*
Make collision testing easy with optional hashCode parameter.
That should not be used! Only by spec/tests.
*/
if (hashCode === undefined) {
// Typical use
hashCode = this.hashCode(key);
} else if (hashCode.length > 0) {
// Testing/Spec - String hash passed, convert to int based hash.
hashCode = this.hashCode(hashCode);
}
hashCode = hashCode % this.maxBucketCount;
if (this.buckets[hashCode] === undefined) {
return undefined;
} else if (this.buckets[hashCode].next === undefined) {
this.buckets[hashCode] = undefined;
} else {
var first = this.buckets[hashCode];
while (
first !== undefined &&
first.next !== undefined &&
first.key !== key
) {
first = first.next;
}
var removedValue = first.data;
// Removing (B)
// (B) : only item in bucket
if (first.prev === undefined && first.next === undefined) {
first = undefined;
return removedValue;
}
// (B) - A - C: start link in bucket
if (first.prev === undefined && first.next !== undefined) {
first.data = first.next.data;
first.key = first.next.key;
if (first.next.next !== undefined) {
first.next = first.next.next;
} else {
first.next = undefined;
}
return removedValue;
}
// A - (B) : end link in bucket
if (first.prev !== undefined && first.next === undefined) {
first.prev.next = undefined;
first = undefined;
return removedValue;
}
// A - (B) - C : middle link in bucket
if (first.prev !== undefined && first.next !== undefined) {
first.prev.next = first.next;
first.next.prev = first.prev;
first = undefined;
return removedValue;
}
}
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/heap.js
================================================
/**
* A binary heap is a complete binary tree which
* satisfies the heap ordering property.
*
* @example
* var Heap = require('path-to-algorithms/src/data-structures/heap').Heap;
*
* var heap = new Heap(function(a, b) {
* return a.birthyear - b.birthyear;
* });
*
* heap.add({
* name: 'John',
* birthyear: 1981
* });
* heap.add({
* name: 'Pavlo',
* birthyear: 2000
* });
* heap.add({
* name: 'Garry',
* birthyear: 1989
* });
* heap.add({
* name: 'Derek',
* birthyear: 1990
* });
* heap.add({
* name: 'Ivan',
* birthyear: 1966
* });
*
* console.log(heap.extract()); // { name: 'Pavlo', birthyear: 2000 }
* console.log(heap.extract()); // { name: 'Derek', birthyear: 1990 }
* console.log(heap.extract()); // { name: 'Garry', birthyear: 1989 }
* console.log(heap.extract()); // { name: 'John', birthyear: 1981 }
* console.log(heap.extract()); // { name: 'Ivan', birthyear: 1966 }
*
* @module data-structures/heap
*/
(function (exports) {
'use strict';
/**
* Minimum heap constructor.
*
* @public
* @constructor
* @param {Function} cmp Function used for comparison between the elements.
*/
exports.Heap = function (cmp) {
this._heap = [];
if (typeof cmp === 'function') {
this._cmp = cmp;
} else {
this._cmp = function (a, b) {
return a - b;
};
}
};
/**
* Exchange indexes with start index given as argument
* to turn the tree into a valid heap. On a single call
* this method maintains only a single "branch" of the heap.<br><br>
*
* Time complexity: O(log N).
*
* @private
* @param {Number} index The parent.
*/
exports.Heap.prototype._heapify = function (index) {
var extr = index;
var left = 2 * index + 1;
var right = 2 * index + 2;
var temp;
if (left < this._heap.length &&
this._cmp(this._heap[left], this._heap[index]) > 0) {
extr = left;
}
if (right < this._heap.length &&
this._cmp(this._heap[right], this._heap[index]) > 0 &&
this._cmp(this._heap[right], this._heap[left]) > 0) {
extr = right;
}
if (index !== extr) {
temp = this._heap[index];
this._heap[index] = this._heap[extr];
this._heap[extr] = temp;
this._heapify(extr);
}
};
/**
* Changes the key.<br><br>
* Complexity: O(log N).
*
* @public
* @param {Number} index Index of the value which should be changed.
* @param {Number|Object} value New value according to the index.
* @return {Number} New position of the element.
*/
exports.Heap.prototype.changeKey = function (index, value) {
this._heap[index] = value;
var elem = this._heap[index];
var parent = Math.floor(index / 2);
var temp;
if (elem !== undefined) {
while (parent >= 0 && this._cmp(elem, this._heap[parent]) > 0) {
temp = this._heap[parent];
this._heap[parent] = elem;
this._heap[index] = temp;
index = parent;
parent = Math.floor(parent / 2);
}
this._heapify(index);
}
return parent;
};
/**
* Updates a given node. This operation is useful
* in algorithms like Dijkstra, A* where we need
* to decrease/increase value of the given node.
*
* @public
* @param {Number|Object} node Node which should be updated.
*/
exports.Heap.prototype.update = function (node) {
var idx = this._heap.indexOf(node);
if (idx >= 0) {
this.changeKey(idx, node);
}
};
/**
* Adds new element to the heap.<br><br>
* Complexity: O(log N).
*
* @public
* @param {Number|Object} value Value which will be inserted.
* @return {Number} Index of the inserted value.
*/
exports.Heap.prototype.add = function (value) {
this._heap.push(value);
return this.changeKey(this._heap.length - 1, value);
};
/**
* Returns current value which is on the top of the heap.<br><br>
* Complexity: O(1).
*
* @public
* @return {Number|Object} Current top value.
*/
exports.Heap.prototype.top = function () {
return this._heap[0];
};
/**
* Removes and returns the current extremum value
* which is on the top of the heap.<br><br>
* Complexity: O(log N).
*
* @public
* @returns {Number|Object} The extremum value.
*/
exports.Heap.prototype.extract = function () {
if (!this._heap.length) {
throw 'The heap is already empty!';
}
var extr = this._heap.shift();
this._heapify(0);
return extr;
};
exports.Heap.prototype.getCollection = function () {
return this._heap;
};
/**
* Checks or heap is empty.
*
* @public
* @returns {Boolean} Returns true if heap is empty.
*/
exports.Heap.prototype.isEmpty = function () {
return !this._heap.length;
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/interval-tree.js
================================================
/**
* Interval tree is an ordered tree data structure to hold intervals.
*
* @example
*
* var IT = require('path-to-algorithms/src/data-structures/interval-tree');
* var intervalTree = new IT.IntervalTree();
*
* intervalTree.add([0, 100]);
* intervalTree.add([101, 200]);
* intervalTree.add([10, 50]);
* intervalTree.add([120, 220]);
*
* console.log(intervalTree.contains(150)); // true
* console.log(intervalTree.contains(250)); // false
* console.log(intervalTree.intersects([210, 310])); // true
* console.log(intervalTree.intersects([310, 320])); // false
*
* @module data-structures/interval-tree
*/
(function (exports) {
'use strict';
/**
* Node which describes an interval.
*
* @public
* @constructor
* @param {Number} start Start of the interval.
* @param {Number} end End of the interval.
* @param {Node} left Left child node.
* @param {Node} right Right child node.
*/
exports.Node = function (start, end, left, right) {
/**
* Node interval.
* @member {Array}
*/
this.interval = [start, end];
/**
* Max endpoint in subtree which starts from this node.
* @member {Number}
*/
this.max = -Infinity;
/**
* Parent node.
* @member {Node}
*/
this.parentNode = null;
/**
* Left child node.
* @member {Node}
*/
this.left = left;
/**
* Right child node.
* @member {Node}
*/
this.right = right;
};
/**
* Interval tree.
*
* @public
* @constructor
*/
exports.IntervalTree = function () {
/**
* Root node of the tree.
* @member {Node}
*/
this.root = null;
};
function addNode(node, side, interval) {
var child = new exports.Node(interval[0], interval[1]);
child.max = interval[1];
child.parentNode = node;
node[side] = child;
if (node.max < interval[1]) {
while (child) {
if (child.max < interval[1]) {
child.max = interval[1];
}
child = child.parentNode;
}
}
}
function addHelper(node, interval) {
if (node.interval[0] > interval[0]) {
if (node.left) {
addHelper(node.left, interval);
} else {
addNode(node, 'left', interval);
}
} else {
if (node.right) {
addHelper(node.right, interval);
} else {
addNode(node, 'right', interval);
}
}
}
/**
* Add new interval to the tree.
*
* @public
* @param {Array} intreval Array with start and end points of the interval.
*/
exports.IntervalTree.prototype.add = function (interval) {
if (!this.root) {
this.root = new exports.Node(interval[0], interval[1]);
this.root.max = interval[1];
return;
}
addHelper(this.root, interval);
};
function contains(point, node) {
if (!node) {
return false;
}
if (node.interval[0] <= point && node.interval[1] >= point) {
return true;
}
var result = false;
var temp;
['left', 'right'].forEach(function (key) {
temp = node[key];
if (temp) {
if (temp.max > point) {
result = result || contains(point, temp);
}
}
});
return result;
}
/**
* Checks or point belongs to at least one intarval from the tree.<br><br>
* Complexity: O(log N).
*
* @public
* @method
* @param {Number} point Point which should be checked.
* @return {Boolean} True if point belongs to one of the intervals.
*/
exports.IntervalTree.prototype.contains = function (point) {
return contains(point, this.root);
};
function intersects(a, b) {
return (a[0] <= b[0] && a[1] >= b[0]) || (a[0] <= b[1] && a[1] >= b[1]) ||
(b[0] <= a[0] && b[1] >= a[0]) || (b[0] <= a[1] && b[1] >= a[1]);
}
function intersectsHelper(interval, node) {
if (!node) {
return false;
}
if (intersects(node.interval, interval)) {
return true;
}
var result = false;
var temp;
['left', 'right'].forEach(function (side) {
temp = node[side];
if (temp && temp.max >= interval[0]) {
result = result || intersectsHelper(interval, temp);
}
});
return result;
}
/**
* Checks or interval belongs to at least one intarval from the tree.<br><br>
* Complexity: O(log N).
*
* @public
* @method
* @param {Array} interval Interval which should be checked.
* @return {Boolean} True if interval intersects with one of the intervals.
*/
exports.IntervalTree.prototype.intersects = function (interval) {
return intersectsHelper(interval, this.root);
};
function heightHelper(node) {
if (!node) {
return 0;
}
return 1 + Math.max(heightHelper(node.left), heightHelper(node.right));
}
/**
* Returns height of the tree.
*
* @public
* @method
* @return {Number} Height of the tree.
*/
exports.IntervalTree.prototype.height = function () {
return heightHelper(this.root);
};
/**
* Returns node with the max endpoint in subtree.
*
* @public
* @method
* @param {Node} node Root node of subtree.
* @return {Node} Node with the largest endpoint.
*/
exports.IntervalTree.prototype.findMax = function (node) {
var stack = [node];
var current;
var max = -Infinity;
var maxNode;
while (stack.length) {
current = stack.pop();
if (current.left) {
stack.push(current.left);
}
if (current.right) {
stack.push(current.right);
}
if (current.interval[1] > max) {
max = current.interval[1];
maxNode = current;
}
}
return maxNode;
};
// adjust the max value
exports.IntervalTree.prototype._removeHelper = function (interval, node) {
if (!node) {
return;
}
if (node.interval[0] === interval[0] &&
node.interval[1] === interval[1]) {
// When left and right children exists
if (node.left && node.right) {
var replacement = node.left;
while (replacement.left) {
replacement = replacement.left;
}
var temp = replacement.interval;
replacement.interval = node.interval;
node.interval = temp;
this._removeHelper(replacement.interval, node);
} else {
// When only left or right child exists
var side = 'left';
if (node.right) {
side = 'right';
}
var parentNode = node.parentNode;
if (parentNode) {
if (parentNode.left === node) {
parentNode.left = node[side];
} else {
parentNode.right = node[side];
}
if (node[side]) {
node[side].parentNode = parentNode;
}
} else {
this.root = node[side];
// last node removed
if (this.root) {
this.root.parentNode = null;
}
}
}
// Adjust the max value
var p = node.parentNode;
if (p) {
var maxNode = this.findMax(p);
var max = maxNode.interval[1];
while (maxNode) {
if (maxNode.max === node.interval[1]) {
maxNode.max = max;
maxNode = maxNode.parentNode;
} else {
maxNode = false;
}
}
}
} else {
// could be optimized
this._removeHelper(interval, node.left);
this._removeHelper(interval, node.right);
}
};
/**
* Remove interval from the tree.
*
* @public
* @method
* @param {Array} intreval Array with start and end of the interval.
*/
exports.IntervalTree.prototype.remove = function (interval) {
return this._removeHelper(interval, this.root);
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/linked-list.js
================================================
/**
* Linked list.
*
* @example
*
* var LL = require('path-to-algorithms/src/data-structures/linked-list');
*
* var linkedList = new LL.LinkedList();
*
* linkedList.push({
* name: 'John',
* birthyear: 1981
* });
* linkedList.push({
* name: 'Pavlo',
* birthyear: 2000
* });
* linkedList.push({
* name: 'Garry',
* birthyear: 1989
* });
* linkedList.push({
* name: 'Derek',
* birthyear: 1990
* });
* linkedList.push({
* name: 'Ivan',
* birthyear: 1966
* });
*
* console.log(linkedList.shift().data); // { name: 'John', birthyear: 1981 }
* console.log(linkedList.pop().data); // { name: 'Ivan', birthyear: 1966 }
*
* @module data-structures/linked-list
*/
(function (exports) {
'use strict';
/**
* Linked list node.
*
* @public
* @constructor
* @param {Object} data Data of the node.
*/
exports.Node = function (data) {
/**
* Data of the node.
* @member {Object}
*/
this.data = data;
/**
* Next node.
* @member {Node}
*/
this.next = null;
/**
* Previous node.
* @member {Node}
*/
this.prev = null;
};
/**
* Linked list.
*
* @public
* @constructor
*/
exports.LinkedList = function () {
this.first = null;
this.last = null;
};
/**
* Add data to the end of linked list.
*
* @public
* @method
* @param {Object} data Data which should be added.
*/
exports.LinkedList.prototype.push = function (data) {
var node = new exports.Node(data);
if (this.first === null) {
this.first = this.last = node;
} else {
var temp = this.last;
this.last = node;
node.prev = temp;
temp.next = node;
}
};
/**
* Add data to the beginning of linked list.
*
* @public
* @method
* @param {Object} data Data which should be added.
*/
exports.LinkedList.prototype.unshift = function (data) {
var node = new exports.Node(data);
if (this.first === null) {
this.first = this.last = node;
} else {
var temp = this.first;
this.first = node;
node.next = temp;
temp.prev = node;
}
};
/**
* In order traversal of the linked list.
*
* @public
* @method
* @param {Function} cb Callback which should be executed on each node.
*/
exports.LinkedList.prototype.inorder = function (cb) {
var temp = this.first;
while (temp) {
cb(temp);
temp = temp.next;
}
};
/**
* Remove data from the linked list.
*
* @public
* @method
* @param {Object} data Data which should be removed.
* @return {Boolean} Returns true if data has been removed.
*/
exports.LinkedList.prototype.remove = function (data, equals) {
if (this.first === null) {
return false;
}
var temp = this.first;
var next;
var prev;
while (temp) {
var dataFound = equals ? equals(temp.data, data) : temp.data === data;
if (dataFound) {
next = temp.next;
prev = temp.prev;
if (next) {
next.prev = prev;
}
if (prev) {
prev.next = next;
}
if (temp === this.first) {
this.first = next;
}
if (temp === this.last) {
this.last = prev;
}
return true;
}
temp = temp.next;
}
return false;
};
/**
* Check if linked list contains cycle.
*
* @public
* @method
* @return {Boolean} Returns true if linked list contains cycle.
*/
exports.LinkedList.prototype.hasCycle = function () {
var fast = this.first;
var slow = this.first;
while (true) {
if (fast === null) {
return false;
}
fast = fast.next;
if (fast === null) {
return false;
}
fast = fast.next;
slow = slow.next;
if (fast === slow) {
return true;
}
}
};
/**
* Return last node from the linked list.
*
* @public
* @method
* @return {Node} Last node.
*/
exports.LinkedList.prototype.pop = function () {
if (this.last === null) {
return null;
}
var temp = this.last;
this.last = this.last.prev;
return temp;
};
/**
* Return first node from the linked list.
*
* @public
* @method
* @return {Node} First node.
*/
exports.LinkedList.prototype.shift = function () {
if (this.first === null) {
return null;
}
var temp = this.first;
this.first = this.first.next;
return temp;
};
/**
* Reverses the linked list recursively
*
* @public
* @method
*/
exports.LinkedList.prototype.recursiveReverse = function () {
function inverse(current, next) {
if (!next) {
return;
}
inverse(next, next.next);
next.prev = next.next;
next.next = current;
}
if (!this.first) {
return;
}
inverse(this.first, this.first.next);
this.first.prev = this.first.next;
this.first.next = null;
var temp = this.first;
this.first = this.last;
this.last = temp;
};
/**
* Reverses the linked list iteratively
*
* @public
* @method
*/
exports.LinkedList.prototype.reverse = function () {
if (!this.first || !this.first.next) {
return;
}
var current = this.first
var next
do {
next = current.next
current.next = current.prev
current.prev = next
current = next
} while (next)
var tmp = this.first
this.first = this.last
this.last = tmp
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/red-black-tree.js
================================================
/**
* Red-Black tree is a data structure which is
* a type of self-balancing binary search tree.
*
* @example
*
* var RBTree = require('../src/data-structures/red-black-tree').RBTree;
* var rbTree = new RBTree();
*
* rbTree.put(1981, {
* name: 'John',
* surname: 'Smith'
* });
* rbTree.put(2000, {
* name: 'Pavlo',
* surname: 'Popov'
* });
* rbTree.put(1989, {
* name: 'Garry',
* surname: 'Fisher'
* });
* rbTree.put(1990, {
* name: 'Derek',
* surname: 'Anderson'
* });
*
* console.log(rbTree.get(1989)); // { name: 'Garry', surname: 'Fisher' }
*
* @module data-structures/red-black-tree
*/
(function (exports) {
'use strict';
/**
* Enum for the different colors
*/
var Colors = {
RED: 0,
BLACK: 1
};
exports.Colors = Colors;
/**
* Node of the Red-Black tree.
*
* @private
* @constructor
* @param {Number} key Key of the node.
* @param {Object} value Value assigned to the node.
* @param {Node} left Left node.
* @param {Node} right Right node.
* @param {Number} color Node color.
*/
function Node(key, value, left, right, color) {
this._key = key;
this._left = left;
this._right = right;
this._value = value;
this._color = color;
}
/**
* Check or node is red.
*
* @private
* @method
* @return {Boolean} Returns true if node is red.
*/
Node.prototype.isRed = function () {
return this._color === Colors.RED;
};
/**
* Changes node color.
*
* @private
* @method
*/
Node.prototype.flipColor = function () {
if (this._color === Colors.RED) {
this._color = Colors.BLACK;
} else {
this._color = Colors.RED;
}
};
/**
* Creates getters and setters for the properties:
* key, value, left, right and color.
*/
'key value left right color'
.split(' ')
.forEach(function (key) {
var valueName = key.substr(0, 1).toUpperCase() + key.substr(1, key.length);
Node.prototype['get' + valueName] = function () {
return this['_' + key];
};
Node.prototype['set' + valueName] = function (val) {
this['_' + key] = val;
};
});
exports.Node = Node;
/**
* Red-Black Tree.
*
* @public
* @constructor
*/
exports.RBTree = function () {
this._root = null;
};
/**
* Add value associated with a given key.<br><br>
* Complexity: O(log N).
*
* @public
* @method
* @param {Number} key Key.
* @param {Object} value Value.
*/
exports.RBTree.prototype.put = function (key, value) {
this._root = this._put(key, value, this._root);
this._root.setColor(Colors.BLACK);
};
/**
* Returns true or false depending on whether
* given node is red.
*
* @private
* @method
* @param {Node} node Node which sould be checked.
* @return Returns true if node is red.
*/
exports.RBTree.prototype.isRed = function (node) {
if (!node) {
return false;
}
return node.isRed();
};
/**
* Helper function for insertion of given key,
* value pair into the Red-Black tree.
*
* @private
* @method
* @param {Number} key Key.
* @param {Object} value Value.
* @param {Node} node Node.
*/
exports.RBTree.prototype._put = function (key, value, node) {
var newRoot = node;
if (node === null) {
return new Node(key, value, null, null, Colors.RED);
}
if (node.getKey() > key) {
node.setLeft(this._put(key, value, node.getLeft()));
} else if (node.getKey() < key) {
node.setRight(this._put(key, value, node.getRight()));
} else {
node.setValue(value);
}
if (this.isRed(node.getRight()) && !this.isRed(node.getLeft())) {
newRoot = this._rotateLeft(node);
}
if (this.isRed(node.getLeft()) && this.isRed(node.getLeft().getLeft())) {
newRoot = this._rotateRight(node);
}
if (this.isRed(node.getLeft()) && this.isRed(node.getRight())) {
this._flipColors(node);
}
return newRoot;
};
/**
* Flip the colors of the both neighbours of given node.<br><br>
* Complexity: O(1).
*
* @private
* @method
* @param {Node} node Node.
*/
exports.RBTree.prototype._flipColors = function (node) {
node.getLeft().flipColor();
node.getRight().flipColor();
};
/*
* Rotates given node to the left.<br><br>
* Complexity: O(1).
*
* @private
* @method
* @param {Node} node Node.
* @return {Node} Right node.
*/
exports.RBTree.prototype._rotateLeft = function (node) {
var x = node.getRight();
if (x !== null) {
var temp = x.getLeft();
node.setRight(temp);
x.setLeft(node);
x.setColor(node.getColor());
node.setColor(Colors.RED);
}
return x;
};
/*
* Rotates given node to the right.<br><br>
* Complexity: O(1).
*
* @private
* @method
* @param {Node} node Node.
* @return {Node} Left node.
*/
exports.RBTree.prototype._rotateRight = function (node) {
var x = node.getLeft();
if (x !== null) {
var temp = x.getRight();
node.setLeft(temp);
x.setRight(node);
x.setColor(node.getColor());
node.setColor(Colors.RED);
}
return x;
};
/**
* Get value by the given key.<br><br>
* Complexity: O(log N).
*
* @public
* @param {Number} key A key to be searched for.
* @return {Object} A value which will be returned based on the key.
*/
exports.RBTree.prototype.get = function (key) {
return this._get(this._root, key);
};
/**
* Get value by the given key.<br><br>
*
* @private
* @param {Node} node Node to start with.
* @param {Number} key A key to be searched for.
* @return {Object} A value which will be returned based on the key.
*/
exports.RBTree.prototype._get = function (node, key) {
if (node === null) {
return undefined;
}
if (node.getKey() === key) {
return node.getValue();
}
if (node.getKey() > key) {
return this._get(node.getLeft(), key);
} else {
return this._get(node.getRight(), key);
}
};
/**
* Get Level Order Traversal for the given Red Black Tree,
* returns 'Tree is empty' string when tree has no Nodes.
* Complexity: O(N).
*
* @public
* @return {String} The keys of the tree in level order traversal.
*
*/
exports.RBTree.prototype.levelOrderTraversal = function () {
var queue = [];
var levelOrderString = '';
if (this._root){
queue.push(this._root);
} else {
levelOrderString = ' Tree is empty';
}
while (queue.length !== 0){
var tempNode = queue.shift();
levelOrderString += ' ' + tempNode.getKey();
if (tempNode.getLeft() !== null){
queue.push(tempNode.getLeft());
}
if (tempNode.getRight() !== null){
queue.push(tempNode.getRight());
}
}
return 'Level Order Traversal -:' + levelOrderString;
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/segment-tree.js
================================================
/**
* Implementation of a segment tree.
*
* @example
* var SegmentTree = require('path-to-algorithms/src/data-structures'+
* '/segment-tree').SegmentTree;
*
* var tree = SegmentTree.indexArray([-1, 2, 4, 0], Infinity, function (a, b) {
* return Math.min(a, b);
* });
*
* @public
* @constructor
* @param {any} placeholder A placeholder value dpendent on the aggregate.
* @param {Function} aggregate Generates the values for the intermediate nodes.
* @module data-structures/segment-tree
*/
(function (exports) {
'use strict';
/**
* SegmentTree constructor.
*
* @public
* @constructor
* @param {any} invalidValue Invalid value to be returned depending
* on the aggregate.
* @param {Function} aggregate Function to generate the intermediate
* values in the tree.
*/
function SegmentTree(invalidValue, aggregate) {
this._data = [];
this._original = null;
this._invalidValue = invalidValue;
this._aggregate = aggregate;
}
/**
* Creates a segment tree using an array passed as element.
*
* @static
* @public
* @param {Array} array Array to be indexed.
* @param {Function} aggregate Function used for generation of
* intermediate nodes.
*/
SegmentTree.indexArray = function (array, placeholder, aggregate) {
var segmentize = function (original, data, lo, hi, idx) {
if (lo === hi) {
data[idx] = original[lo];
} else {
var mid = Math.floor((lo + hi) / 2);
var left = 2 * idx + 1;
var right = 2 * idx + 2;
segmentize(original, data, lo, mid, left);
segmentize(original, data, mid + 1, hi, right);
data[idx] = aggregate(data[left], data[right]);
}
};
var result = [];
if (array && array.length) {
segmentize(array, result, 0, array.length - 1, 0);
}
var tree = new SegmentTree(placeholder, aggregate);
tree._data = result;
tree._original = array;
return tree;
};
/**
* Queries the SegmentTree in given range based on the set aggregate.
*
* @param {Number} start The start index of the interval.
* @param {Number} end The end index of the interval.
*/
SegmentTree.prototype.query = function (start, end) {
if (start > end) {
throw new Error('The start index should be smaller by the end index');
}
var findEl = function (originalArrayStart, originalArrayEnd, current) {
if (start > originalArrayEnd) {
return this._invalidValue;
}
if (end < originalArrayStart) {
return this._invalidValue;
}
if (start === originalArrayStart && end === originalArrayEnd ||
originalArrayStart === originalArrayEnd) {
return this._data[current];
}
var originalArrayMid =
Math.floor((originalArrayStart + originalArrayEnd) / 2);
return this._aggregate(
findEl(originalArrayStart, originalArrayMid, 2 * current + 1),
findEl(originalArrayMid + 1, originalArrayEnd, 2 * current + 2)
);
}.bind(this);
return findEl(0, this._original.length - 1, 0, this._aggregate);
};
exports.SegmentTree = SegmentTree;
}(typeof window === 'undefined' ? module.exports : window));
================================================
FILE: src/data-structures/size-balanced-tree.js
================================================
/**
* Size balanced tree is a data structure which is
* a type of self-balancing binary search tree that use
* the tree size attribute for re-balancing the tree.
*
* @example
*
* var SBTree = require('../src/data-structures/size-balanced-tree').SBTree;
* var sbTree = new SBTree();
*
* var treeNode = sbTree.push({
* name: 'John',
* surname: 'Smith'
* });
* sbTree.insert(0, {
* name: 'Pavlo',
* surname: 'Popov'
* });
* sbTree.insert(1, {
* name: 'Garry',
* surname: 'Fisher'
* });
* sbTree.insert(0, {
* name: 'Derek',
* surname: 'Anderson'
* });
*
* console.log(sbTree.get(0)); // { name: 'Derek', surname: 'Anderson' }
*
* @module data-structures/size-balanced-tree
*/
function CreateSBTreeClass (Node, Nil, updateChild) {
'use strict';
function LeftRotate(node, childNode) {
/*
Before rotate:
node
/ \
NL childNode
/ \
CL CR
After rotate:
childNode
/ \
node CR
/ \
NL CL
*/
node.right = childNode.left;
if (node.right !== Nil) {
node.right.parent = node;
}
childNode.left = node;
// setting childNode's parent to node's parent
updateChild(node, childNode);
return childNode;
}
function RightRotate(node, childNode) {
/*
Before rotate:
node
/ \
childNode NR
/ \
CL CR
After rotate:
childNode
/ \
CL node
/ \
CR NR
*/
node.left = childNode.right;
if (node.left !== Nil) {
node.left.parent = node;
}
childNode.right = node;
// setting childNode's parent to node's parent
updateChild(node, childNode);
return childNode;
}
function maintain(node, leftChild) {
if (node === Nil) {
return node;
}
var savedNode = node;
if (leftChild) {
if (node.left.left.size > node.right.size) {
node = RightRotate(node, node.left);
} else if (node.left.right.size > node.right.size) {
LeftRotate(node.left, node.left.right);
node = RightRotate(node, node.left);
}
} else {
if (node.right.right.size > node.left.size) {
node = LeftRotate(node, node.right);
} else if (node.right.left.size > node.left.size) {
RightRotate(node.right, node.right.left);
node = LeftRotate(node, node.right);
}
}
if (node === savedNode) {
return node;
}
maintain(node.left, false);
maintain(node.right, true);
node = maintain(node, true);
node = maintain(node, false);
return node;
}
function maintainSizeBalancedTree(node) {
while (node.parent !== Nil) {
var childNode = node;
node = node.parent;
if (node.left === childNode) {
node = maintain(node, true);
} else {
node = maintain(node, false);
}
}
return node;
}
function findNodeAtPos(node, pos) {
while (pos !== node.left.size) {
if (pos < node.left.size) {
node = node.left;
} else {
pos -= node.left.size;
pos -= 1; //The node element should be decrement by 1
node = node.right;
}
}
return node;
}
/**
* Size Balanced Tree.
*
* @public
* @constructor
*/
var SBTree = function () {};
SBTree.prototype = {
_root: Nil,
get size() {
return this._root.size;
},
get root() {
return this._root;
},
binarySearch: function (cmp, value) {
var left = -1;
var right = this.size;
while (left + 1 < right) {
var middle = (left + right) >> 1; // jshint ignore:line
var result = cmp(this.get(middle).value, value);
if (result <= 0) {
left = middle;
} else {
right = middle;
}
}
return left + 1;
},
};
SBTree.prototype.get = function (pos) {
if (pos >= this.size) {
return Nil;
}
return findNodeAtPos(this._root, pos);
};
SBTree.prototype.getIndex = function (node) {
var index = node.left.size;
while (node !== this._root) {
var parent = node.parent;
if (parent.right === node) {
index += parent.left.size + 1;
}
node = parent;
}
return index;
};
SBTree.prototype.shiftDown = function (node) {
var direction = 0;
while (true) {
if (node.left !== Nil && node.right !== Nil) {
switch (direction) {
case 0:
RightRotate(node, node.left);
break;
case 1:
LeftRotate(node, node.right);
break;
}
direction = 1 - direction;
} else if (node.left !== Nil) {
RightRotate(node, node.left);
} else if (node.right !== Nil) {
LeftRotate(node, node.right);
} else {
break; // The node could be able to removed
}
}
};
SBTree.prototype.insertLeafNode = function (node) {
var parent = node.parent;
while (parent !== Nil) {
parent.size = parent.size + 1;
parent = parent.parent;
}
};
SBTree.prototype.removeLeafNode = function (node) {
var parent = node.parent;
while (parent !== Nil) {
parent.size = parent.size - 1;
parent = parent.parent;
}
};
SBTree.prototype.insert = function (pos, value) {
var node = Nil;
var newNode = new Node(value, Nil, Nil, Nil, 1);
if (pos === this.size) {
if (pos > 0) {
node = findNodeAtPos(this._root, pos - 1);
node.right = newNode;
}
} else {
node = findNodeAtPos(this._root, pos);
if (node.left !== Nil) {
this.shiftDown(node);
}
node.left = newNode;
}
newNode.parent = node;
this.insertLeafNode(newNode);
this._root = maintainSizeBalancedTree(newNode);
return newNode;
};
/**
* Push a value to the end of tree.
* Complexity: O(log N).
*
* @public
* @method
* @param {Object} value Value.
*/
SBTree.prototype.push = function (value) {
this.insert(this.size, value);
};
SBTree.prototype.removeNode = function (node) {
this.shiftDown(node);
var maintainNode = node.parent;
if (maintainNode.left === node) {
maintainNode.left = Nil;
} else if (maintainNode.right === node) {
maintainNode.right = Nil;
}
this.removeLeafNode(node);
this._root = maintainSizeBalancedTree(maintainNode);
return node;
};
SBTree.prototype.remove = function (pos) {
if (pos >= this._root.size) {
return Nil; // There is no element to remove
}
var node = findNodeAtPos(this._root, pos);
return this.removeNode(node);
};
return SBTree;
}
(function (exports) {
'use strict';
/**
* Node constructor of the Size-Balanced tree.
*
* @private
* @constructor
* @param {Object} value Value assigned to the node.
* @param {Node} parent Parent node.
* @param {Node} left Left node.
* @param {Node} right Right node.
* @param {Number} size Node's, means the Node count of this .
*/
var NodeConstructor = function (value, parent, left, right, size) {
this.value = value;
this.parent = parent;
this.left = left;
this.right = right;
this.size = size;
};
var createNil = function (Node, value) {
var Nil = new Node(value, null, null, null, 0);
Nil.parent = Nil;
Nil.left = Nil;
Nil.right = Nil;
return Nil;
};
/**
* Update node's size.
*
* @private
* @method
*/
var updateSize = function () {
this.size = this.left.size + this.right.size + 1;
};
// node, childNode must not be Nil,
// if the childNode turn out to be the root, the parent should be Nil
var updateChild = function (node, childNode) {
var parent = node.parent;
node.parent = childNode;
childNode.parent = parent;
node.updateSize();
childNode.updateSize();
if (parent.right === node) {
parent.right = childNode;
parent.updateSize();
} else if (parent.left === node) {
parent.left = childNode;
parent.updateSize();
} // otherwise parent is Nil
};
var Node = function () {
NodeConstructor.apply(this, arguments);
};
Node.prototype.updateSize = updateSize;
var Nil = createNil(Node, null);
exports.NodeConstructor = NodeConstructor;
exports.createNil = createNil;
exports.updateSize = updateSize;
exports.updateChild = updateChild;
exports.CreateSBTreeClass = CreateSBTreeClass;
exports.Node = Node;
exports.Nil = Nil;
exports.SBTree = CreateSBTreeClass(Node, Nil, updateChild);
})(typeof module === 'undefined' ? window : module.exports);
================================================
FILE: src/data-structures/splay-tree.js
================================================
/**
* Splay Tree.
*
* @example
* var STree = require('path-to-algorithms/src/data-structures'+
* '/splay-tree');
* var sTree = new STree.SplayTree();
* sTree.insert(10);
* sTree.insert(5);
* sTree.insert(15);
* sTree.insert(7);
* sTree.insert(12);
* sTree.search(10);
* console.log(sTree._root);
* sTree.remove(10);
* console.log(sTree._root);
* sTree.search(15);
* console.log(sTree._root);
*
* @module data-structures/splay-tree
*/
(function (exports) {
'use strict';
/**
* Node of the tree.
*
* @public
* @constructor
* @param {Number|String} value Value of the node.
* @param {Node} left Left sibling.
* @param {Node} right Right sibling.
* @param {Node} parent Parent of the node.
*/
exports.Node = function (value, left, right, parent) {
/**
* @member {Number|String}
*/
this.value = value;
this._left = left;
this._right = right;
this._parent = parent;
};
/**
* Splay tree.
* {@link http://en.wikipedia.org/wiki/Splay_tree}
* @public
* @constructor
*/
exports.SplayTree = function () {
this._root = null;
};
/**
* Splays a node to the root.<br><br>
*
* @private
* @method
* @param {Node} node Node to be splayed.
* @returns {Node} The same node from the parameter, post splayed.
*/
exports.SplayTree.prototype._splay = function (node) {
while (this._root !== node) {
var hasParent = node._parent !== null;
var hasGrandparent = (hasParent && node._parent._parent !== null);
if (hasParent && hasGrandparent) {
var isLeftChild = node._parent._left === node;
var isParentLeftChild = node._parent._parent._left === node._parent;
if (
(isLeftChild && isParentLeftChild) ||
(!isLeftChild && !isParentLeftChild)
) {
node = this._zigZig(node);
} else {
node = this._zigZag(node);
}
} else {
node = this._zig(node);
}
}
return node;
};
/**
* Performs a zig-zig splay pattern<br><br>
*
* @private
* @method
* @param {Node} node Node to be zig-zig'd.
* @returns {Node} The same node from the parameter, post splayed.
*/
exports.SplayTree.prototype._zigZig = function (node) {
var parent = node._parent;
var grandParent = node._parent._parent;
var greatGrandParent = grandParent._parent !== undefined ?
grandParent._parent : null;
var orientation = (parent._right === node) ? '_right' : '_left';
var oppositeOrientation = (orientation === '_left') ? '_right' : '_left';
var grandParentOrientation = (greatGrandParent !== null &&
greatGrandParent._left === grandParent) ? '_left' : '_right';
// Fix grandparent & great if it exists/not root
if (this._root === grandParent) {
this._root = node;
} else {
greatGrandParent[grandParentOrientation] = node;
}
grandParent._parent = parent;
// Fix grandparent subtree
grandParent[orientation] = parent[oppositeOrientation];
if (grandParent[orientation] !== null) {
grandParent[orientation]._parent = grandParent;
}
// Fix Parent
parent[oppositeOrientation] = grandParent;
parent[orientation] = node[oppositeOrientation];
if (parent[orientation] !== null) {
parent[orientation]._parent = parent;
}
parent._parent = node;
// Fix Curr Node
node[oppositeOrientation] = parent;
if (node === this._root) {
node._parent = null;
} else if (greatGrandParent !== null) {
node._parent = greatGrandParent;
}
return node;
};
/**
* Performs a zig-zag splay pattern<br><br>
*
* @private
* @method
* @param {Node} node Node to be zig-zag'd.
* @returns {Node} The same node from the parameter, post splayed.
*/
exports.SplayTree.prototype._zigZag = function (node) {
var parent = node._parent;
var grandParent = parent._parent;
var greatGrandParent = grandParent._parent !== undefined ?
grandParent._parent : null;
var orientation = (parent._left === node) ? '_left' : '_right';
var oppositeOrientation = (orientation === '_right') ? '_left' : '_right';
var grandParentOrientation = (greatGrandParent !== null &&
greatGrandParent._left === grandParent) ? '_left' : '_right';
// Fix GrandParent
if (this._root === grandParent) {
this._root = node;
} else {
greatGrandParent[grandParentOrientation] = node;
}
grandParent._parent = node;
// Fix GrandParent subtree
grandParent[oppositeOrientation] = node[orientation];
if (grandParent[oppositeOrientation] !== null) {
grandParent[oppositeOrientation]._parent = grandParent;
}
// Fix Parent
parent[orientation] = node[oppositeOrientation];
if (parent[orientation] !== null) {
parent[orientation]._parent = parent;
}
parent._parent = node;
// Fix Curr Node
node[orientation] = grandParent;
node[oppositeOrientation] = parent;
if (this._root === node) {
node._parent = null;
} else if (greatGrandParent !== null) {
node._parent = greatGrandParent;
}
return node;
};
/**
* Performs a zig splay pattern<br><br>
*
* @private
* @method
* @param {Node} node Node to be zig'd.
* @returns {Node} The same node from the parameter, post splayed.
*/
exports.SplayTree.prototype._zig = function (node) {
var parent = node._parent;
var orientation = (parent._right === node) ? '_right' : '_left';
var oppositeOrientation = (orientation === '_right') ? '_left' : '_right';
if (this._root === parent) {
this._root = node;
}
// Fix Parent
parent[orientation] = node[oppositeOrientation];
if (parent[orientation] !== null) {
parent[orientation]._parent = parent;
}
parent._parent = node;
// Fix Curr Node
node[oppositeOrientation] = parent;
node._parent = null;
return node;
};
/**
* Inserts a node into the splay tree.<br><br>
* Time complexity: O(log N) in the average case
* and amortized O(log n) in the worst case.
*
* @public
* @method
* @param {Number|String} value Node value.
* @param {Node} current Current node.
*/
exports.SplayTree.prototype.insert = function (value, current) {
if (this._root === null) {
this._root = new exports.Node(value, null, null, null);
return;
}
var insertKey;
current = current || this._root;
if (current.value > value) {
insertKey = '_left';
} else {
insertKey = '_right';
}
if (!current[insertKey]) {
current[insertKey] = new exports.Node(value, null, null, current);
this._splay(current[insertKey]);
} else {
this.insert(value, current[insertKey]);
}
};
/**
* In-order traversal from the given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.SplayTree.prototype._inorder = function (current, callback) {
if (!current) {
return;
}
this._inorder(current._left, callback);
if (typeof callback === 'function') {
callback(current);
}
this._inorder(current._right, callback);
};
/**
* In-order traversal of the whole Splay Tree.
*
* @public
* @method
* @param {Function} callback Callback which will be
* called for each traversed node.
*/
exports.SplayTree.prototype.inorder = function (callback) {
return this._inorder(this._root, callback);
};
/**
* Post-order traversal from given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which will
* be called for each traversed node
*/
exports.SplayTree.prototype._postorder = function (current, callback) {
if (!current) {
return;
}
if (typeof callback === 'function') {
callback(current);
}
this._postorder(current._left, callback);
this._postorder(current._right, callback);
};
/**
* Post-order traversal of the whole tree.
*
* @public
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.SplayTree.prototype.postorder = function (callback) {
return this._postorder(this._root, callback);
};
/**
* Pre-order traversal of the tree from given node.
*
* @private
* @param {Node} current Node from which to start the traversal.
* @param {Function} callback Callback which
* will be called for each traversed node.
*/
exports.SplayTree.prototype._preorder = function (current, callback) {
if (!current) {
return;
}
if (typeof callback === 'function') {
callback(current);
}
this._preorder(current._left, callback);
this._preorder(current._right, callback);
};
/**
* Pre-order preorder traversal of the whole tree.
*
* @public
* @param {Function} callback Callback which will
* be called for each traversed node.
*/
exports.SplayTree.prototype.preorder = function (callback) {
return this._preorder(this._root, callback);
};
/**
* Finds a node by it's value.<br><br>
* Average time complexity: O(log N).
*
* @public
* @param {Number|String} value of the node which should be found.
*/
exports.SplayTree.prototype.search = function (value) {
var node = this._search(value, this._root);
return this._splay(node);
};
/**
* Finds a node by it's value.<br><br>
* Average time complexity: O(log N).
*
* @public
* @param {Number|String} value of the node which should be found.
*/
exports.SplayTree.prototype._splaylessSearch = function (value) {
return this._search(value, this._root);
};
/**
* Finds a node by it's value in a given sub-tree.
* Average time complexity: O(log N).
*
* @private
* @param {Number|String} value of the node which should be found.
* @param {Node} current node to be checked.
*/
exports.SplayTree.prototype._search = function (value, current) {
if (!current) {
return null;
}
if (current.value === value) {
return current;
}
if (current.value > value) {
return this._search(value, current._left);
}
if (current.value < value) {
return this._search(value, current._right);
}
};
/**
* Replaces given child with new one, for given parent.
*
* @private
* @param {Node} parent Parent node.
* @param {Node} oldChild Child to be replaced.
* @param {Node} newChild Child replacement.
*/
exports.SplayTree.prototype._replaceChild =
function (parent, oldChild, newChild) {
if (!parent) {
this._root = newChild;
this._root._parent = null;
} else {
if (parent._left === oldChild) {
parent._left = newChild;
} else {
parent._right = newChild;
}
if (newChild) {
newChild._parent = parent;
}
}
};
/**
* Removes node with given value from the tree. <br><br>
* Average runtime complexity: O(log N).
*
* @public
* @param {Number|String} value Value to be removed
* @returns {Boolean} True/false depending
* on whether the given node is removed.
*/
exports.SplayTree.prototype.remove = function (value) {
var node = this._splaylessSearch(value);
if (!node) {
return false;
}
if (node._left && node._right) {
var min = this._findMin(node._right);
var temp = node.value;
node.value = min.value;
min.value = temp;
return this.remove(min);
} else {
if (node._parent !== null) {
if (node._left) {
this._replaceChild(node._parent, node, node._left);
} else if (node._right) {
this._replaceChild(node._parent, node, node._right);
} else {
this._replaceChild(node._parent, node, null);
}
this._splay(node._parent);
} else {
this._root = null;
}
return true;
}
};
/**
* Finds the node with minimum value in given sub-tree.
*
* @private
* @param {Node} node Root of the sub-tree.
* @param {Number|String} current Current minimum value of the sub-tree.
* @returns {Node} Node with the minimum value in the sub-tree.
*/
exports.SplayTree.prototype._findMin = function (node, current) {
current = current || {
value: Infinity
};
if (!node) {
return current;
}
if (current.value > node.value) {
current = node;
}
return this._findMin(node._left, current);
};
exports.SplayTree.prototype._isBalanced = function (current) {
if (!current) {
return true;
}
return this._isBalanced(current._left) &&
this._isBalanced(current._right) &&
Math.abs(this._getHeight(current._left) -
this._getHeight(current._right)) <= 1;
};
/**
* Returns whether the Splay Tree is balanced.
*
* @public
* @returns {Boolean} Whether the tree is balanced or not.
*/
exports.SplayTree.prototype.isBalanced = function () {
return this._isBalanced(this._root);
};
/**
* Finds the diameter of the Splay Tree.
*
* @public
* @returns {Number} The longest path in the tree.
*/
exports.SplayTree.prototype.getDiameter = function () {
var getDiameter = function (root) {
if (!root) {
return 0;
}
var leftHeight = this._getHeight(root._left);
var rightHeight = this._getHeight(root._right);
var path = leftHeight + rightHeight + 1;
return Math.max(path, getDiameter(root._left), getDiameter(root._right));
}.bind(this);
return getDiameter(this._root);
};
/**
* Returns the height of the tree.
*
* @public
* @returns {Number} The height of the tree.
*/
exports.SplayTree.prototype.getHeight = function () {
return this._getHeight(this._root);
};
/**
* Recursive worker function for getHeight()
*
* @public
* @param {Node} node The node of the current recursive frame.
* @returns {Number} The height of the tree.
*/
exports.SplayTree.prototype._getHeight = function (node) {
if (!node) {
return 0;
}
return 1 + Math.max(this._getHeight(node._left),
this._getHeight(node._right));
};
/**
* Finds the lowest common ancestor of two nodes.
*
* @public
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.SplayTree.prototype.lowestCommonAncestor =
function (firstNode, secondNode) {
return this._lowestCommonAncestor(firstNode, secondNode, this._root);
};
/**
* Obtains the lowest common ancestor for the given nodes.
*
* @private
* @param {Node} firstNode First node to be considered when checking
* for ancestor.
* @param {Node} secondNode Second node to be considered when checking
* for ancestor.
* @param {Node} current Current node.
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.SplayTree.prototype._lowestCommonAncestor =
function (firstNode, secondNode, current) {
var firstNodeInLeft = this._existsInSubtree(firstNode, current._left);
var secondNodeInLeft = this._existsInSubtree(secondNode, current._left);
var firstNodeInRight = this._existsInSubtree(firstNode, current._right);
var secondNodeInRight = this._existsInSubtree(secondNode, current._right);
if ((firstNodeInLeft && secondNodeInRight) ||
(firstNodeInRight && secondNodeInLeft)) {
return current;
}
if (secondNodeInLeft && firstNodeInLeft) {
return this._lowestCommonAncestor(firstNode, secondNode, current._left);
}
if (secondNodeInRight && secondNodeInLeft) {
return this._lowestCommonAncestor(firstNode, secondNode,
current._right);
}
return null;
};
/**
* Checks if a given node exists in a subtree.
*
* @private
* @param {Node} node Node to check for.
* @param {Node} root Root node of a given subtree.
* @returns {Node} The lowest common ancestor of the two nodes or null.
*/
exports.SplayTree.prototype._existsInSubtree = function (node, root) {
if (!root) {
return false;
}
if (node === root.value) {
return true;
}
return this._existsInSubtree(node, root._left) ||
this._existsInSubtree(node, root._right);
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/data-structures/suffix-tree.js
================================================
(function (exports) {
'use strict';
function Node(val) {
this.value = val;
this.nodes = {};
}
function SuffixTree() {
this.root = new Node();
}
SuffixTree.prototype.addNode = (function () {
function maxPrefix(a, b) {
var res = [];
for (var i = 0; i < Math.min(a.length, b.length); i += 1) {
if (a[i] === b[i]) {
res.push(a[i]);
} else {
return '';
}
}
return res.join('');
}
function addNode(suffix, current) {
// Empty string already exists in the suffix tree
if (!suffix) {
return;
}
// The suffix is already inside the tree
if (current.value === suffix) {
return;
}
// Insert recursively
if (current.nodes[suffix[0]]) {
return addNode(suffix.substr(1, suffix.length),
current.nodes[suffix[0]]);
}
// Find the maximum prefix and split the current node if prefix exists
var prefix = maxPrefix(current.value, suffix);
if (prefix.length) {
var temp = current.value;
var suffixSuffix = suffix.substr(prefix.length, suffix.length);
var currentSuffix = temp.substr(prefix.length, temp.length);
current.value = prefix;
addNode(currentSuffix, current);
addNode(suffixSuffix, current);
// If prefix doesn't exists add new child node
} else {
current.nodes[suffix[0]] = new Node(suffix);
}
}
return function (suffix) {
addNode(suffix, this.root);
};
}());
// O(n^2) or even O(n^3) because of maxPrefix
SuffixTree.prototype.build = function (string) {
this.root.value = string;
for (var i = 1; i < string.length; i += 1) {
this.addNode(string.substr(i, string.length));
}
};
exports.Node = Node;
exports.SuffixTree = SuffixTree;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/data-structures/vertex.js
================================================
(function (exports) {
'use strict';
/**
* Graph vertex.
*
* @constructor
* @public
* @param {Number} id Id of the vertex.
* @module data-structures/vertex
*/
exports.Vertex = function (id) {
this.id = id;
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/graphics/bezier.js
================================================
(function (exports) {
'use strict';
function linearBezier(p0, p1, t) {
return p0 + t * (p1 - p0);
}
function quadraticBezier(p0, p1, p2, t) {
return linearBezier(linearBezier(p0, p1, t), linearBezier(p1, p2, t), t);
}
function cubicBezier(p0, p1, p2, p3, t) {
return linearBezier(quadraticBezier(p0, p1, p2, t), quadraticBezier(p1, p2, p3, t), t);
}
exports.linearBezier = linearBezier;
exports.quadraticBezier = quadraticBezier;
exports.cubicBezier = cubicBezier;
})(typeof exports === 'undefined' ? window : exports);
================================================
FILE: src/graphics/bresenham-line-drawing.js
================================================
(function (exports) {
'use strict';
/**
* Draws (prints) the given coordinates
* @param {number} x The first coordinate of the point
* @param {number} y The second coordinate of the point
*/
function drawPoint(x, y) {
console.log(x, y);
}
/**
* Bresenham's line drawing algorithm.
* It has complexity O(n)
* @param {number} x1 The first coordinate of the beginning of the line
* @param {number} y1 The second coordinate of the beginning of the line
* @param {number} x2 The first coordinate of the end of the line
* @param {number} y2 The second coordinate of the end of the line
* @param {function} draw Optional custom drawing function.
*/
function drawLine(x1, y1, x2, y2, draw) {
var drawPointStrategy = draw || drawPoint;
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var cx = (x1 < x2) ? 1 : -1;
var cy = (y1 < y2) ? 1 : -1;
var error = dx - dy;
var doubledError;
while (x1 !== x2 || y1 !== y2) {
drawPointStrategy(x1, y1);
doubledError = error + error;
if (doubledError > -dy) {
error -= dy;
x1 += cx;
}
if (doubledError < dx) {
error += dx;
y1 += cy;
}
}
}
exports.drawLine = drawLine;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/graphics/graham.js
================================================
(function(exports) {
'use strict';
const slope = (p, a) => (a.y - p.y) / (a.x - p.x);
const dist = (a, b) => Math.sqrt((b.y - a.y) * (b.y - a.y) + (b.x - a.x) * (b.x - a.x));
const sort = (p, memo, a, b) => {
const sa = slope(p, a);
const sb = slope(p, b);
[[sa, a], [sb, b]].forEach(e => {
const el = memo.get(e[0]);
if (!el || dist(p, el) < dist(p, e[1])) {
memo.set(e[0], e[1]);
}
});
return sa - sb;
};
const ccw = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
/**
* Graham's algorithm for calculating the convex hull.
*
* @public
* @module graphics/graham
* @param {Array} all
* @returns {Array}
*
* @example
* const points = [
* { x: 0, y: 0 },
* { x: 1, y: 0 },
* { x: 0, y: 1 },
* { x: 0.15, y: 0.15 },
* { x: 0.5, y: 0.5 }
* ];
* const list = convexHull(points);
* // [{ x: 0, y: 0 },
* // { x: 1, y: 0 },
* // { x: 0.5, y: 0.5 },
* // { x: 0, y: 1 }]
*/
const convexHull = all => {
if (!all.length) {
return [];
}
const p = all.reduce((a, c) => {
if (a.y < c.y) {
return a;
}
if (a.y > c.y) {
return c;
}
if (a.x < c.x) {
return a;
}
return c;
});
const memo = new Map();
const stack = [];
all
.sort(sort.bind(null, p, memo))
.filter(c => memo.get(slope(p, c)) === c)
.forEach(p => {
while (stack.length > 1 && ccw(stack[stack.length - 2], stack[stack.length - 1], p) < 0) {
stack.pop();
}
stack.push(p);
});
return stack;
};
exports.convexHull = convexHull;
})(typeof exports === 'undefined' ? window : exports);
================================================
FILE: src/graphs/others/tarjan-connected-components.js
================================================
(function (exports) {
'use strict';
/**
* Tarjan's algorithm for finding the connected components in a graph.<br><br>
* Time complexity: O(|E| + |V|) where E is a number of edges and |V|
* is the number of nodes.
*
* @public
* @module graphs/others/tarjan-connected-components
* @param {Array} graph Adjacency list, which represents the graph.
* @returns {Array} Connected components.
*
* @example
* var tarjanConnectedComponents =
* require('path-to-algorithms/src/graphs/' +
* 'others/tarjan-connected-components').tarjanConnectedComponents;
* var graph = {
* v1: ['v2', 'v5'],
* v2: [],
* v3: ['v1', 'v2', 'v4', 'v5'],
* v4: [],
* v5: []
* };
* var vertices = topsort(graph); // ['v3', 'v4', 'v1', 'v5', 'v2']
*/
function tarjanConnectedComponents(graph) {
graph = graph || {};
const indexes = {};
const lowIndexes = {};
const onStack = {};
const result = [];
const stack = [];
var index = 1;
const connectedComponent = function (node) {
stack.push(node);
onStack[node] = true;
indexes[node] = index;
lowIndexes[node] = index;
index += 1;
graph[node].forEach(function (n) {
if (indexes[n] === undefined) {
connectedComponent(n);
lowIndexes[node] = Math.min(lowIndexes[n], lowIndexes[node]);
} else if (onStack[n]) {
lowIndexes[node] = Math.min(lowIndexes[node], indexes[n]);
}
});
// This is a "root" node
const cc = [];
if (indexes[node] === lowIndexes[node]) {
var current;
do {
current = stack.pop();
onStack[current] = false;
cc.push(current);
} while (stack.length > 0 && node !== current);
result.push(cc);
}
};
Object.keys(graph)
.forEach(function (n) {
if (!indexes[n]) {
connectedComponent(n);
}
});
return result;
}
exports.tarjanConnectedComponents = tarjanConnectedComponents;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/graphs/others/topological-sort.js
================================================
(function (exports) {
'use strict';
var topologicalSort = (function () {
function topologicalSortHelper(node, visited, temp, graph, result) {
temp[node] = true;
var neighbors = graph[node];
for (var i = 0; i < neighbors.length; i += 1) {
var n = neighbors[i];
if (temp[n]) {
throw new Error('The graph is not a DAG');
}
if (!visited[n]) {
topologicalSortHelper(n, visited, temp, graph, result);
}
}
temp[node] = false;
visited[node] = true;
result.push(node);
}
/**
* Topological sort algorithm of a directed acyclic graph.<br><br>
* Time complexity: O(|E| + |V|) where E is a number of edges
* and |V| is the number of nodes.
*
* @public
* @module graphs/others/topological-sort
* @param {Array} graph Adjacency list, which represents the graph.
* @returns {Array} Ordered vertices.
*
* @example
* var topsort =
* require('path-to-algorithms/src/graphs/' +
* 'others/topological-sort').topologicalSort;
* var graph = {
* v1: ['v2', 'v5'],
* v2: [],
* v3: ['v1', 'v2', 'v4', 'v5'],
* v4: [],
* v5: []
* };
* var vertices = topsort(graph); // ['v3', 'v4', 'v1', 'v5', 'v2']
*/
return function (graph) {
var result = [];
var visited = [];
var temp = [];
for (var node in graph) {
if (!visited[node] && !temp[node]) {
topologicalSortHelper(node, visited, temp, graph, result);
}
}
return result.reverse();
};
}());
exports.topologicalSort = topologicalSort;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/graphs/searching/bfs.js
================================================
(function (exports) {
'use strict';
var bfs = (function () {
function buildPath(parents, targetNode) {
var result = [targetNode];
while (parents[targetNode] !== null) {
targetNode = parents[targetNode];
result.push(targetNode);
}
return result.reverse();
}
/**
* Breath-First graph searching algorithm.
* Returns the shortest path between startNode and targetNode.<br><br>
* Time complexity: O(|V|^2).
*
* @public
* @module graphs/searching/bfs
* @param {Array} graph Adjacency matrix, which represents the graph.
* @param {Number} startNode Start node.
* @param {Number} targetNode Target, which should be reached.
* @returns {Array} Shortest path from startNode to targetNode.
*
* @example
* var bfs = require('path-to-algorithms/src/graphs/searching/bfs').bfs;
* var graph = [[1, 1, 0, 0, 1, 0],
* [1, 0, 1, 0, 1, 0],
* [0, 1, 0, 1, 0, 0],
* [0, 0, 1, 0, 1, 1],
* [1, 1, 0, 1, 0, 0],
* [0, 0, 0, 1, 0, 0]];
* var shortestPath = bfs(graph, 1, 5); // [1, 2, 3, 5]
*/
return function (graph, startNode, targetNode) {
var parents = [];
var queue = [];
var visited = [];
var current;
queue.push(startNode);
parents[startNode] = null;
visited[startNode] = true;
while (queue.length) {
current = queue.shift();
if (current === targetNode) {
return buildPath(parents, targetNode);
}
for (var i = 0; i < graph.length; i += 1) {
if (i !== current && graph[current][i] && !visited[i]) {
parents[i] = current;
visited[i] = true;
queue.push(i);
}
}
}
return null;
};
}());
exports.bfs = bfs;
}((typeof window === 'undefined') ? module.exports : window));
================================================
FILE: src/graphs/searching/dfs.js
================================================
(function (exports) {
'use strict';
var dfs = (function () {
function hasPath(graph, current, goal) {
var stack = [];
var visited = [];
var node;
stack.push(current);
visited[current] = true;
while (stack.length) {
node = stack.pop();
if (node === goal) {
return true;
}
for (var i = 0; i < graph[node].length; i += 1) {
if (graph[node][i] && !visited[i]) {
stack.push(i);
visited[i] = true;
}
}
}
return false;
}
/**
* Depth-First graph searching algorithm.
* Returns whether there's a path between two nodes in a graph.<br><br>
* Time complexity: O(|V|^2).
*
* @module graphs/searching/dfs
* @public
* @param {Array} graph Adjacency matrix, which represents the graph.
* @param {Number} start Start node.
* @param {Number} goal Target node.
* @return {Boolean} Returns true if path between two nodes exists.
*
* @example
* var dfs = require('../src/graphs/searching/dfs').dfs;
* var graph = [[1, 1, 0, 0, 1, 0],
* [1, 0, 1, 0, 1, 0],
* [0, 1, 0, 1, 0, 0],
* [0, 0, 1, 0, 1, 1],
* [1, 1, 0, 1, 0, 0],
* [0, 0, 0, 1, 0, 0]];
* var pathExists = dfs(graph, 1, 5); // true
*/
return function (graph, start, goal) {
return hasPath(graph, start, goal);
};
}());
exports.dfs = dfs;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/graphs/shortest-path/bellman-ford.js
================================================
/**
* Bellman–Ford algorithm computes shortest paths from a single source
* vertex to all of the other vertices in a weighted digraph
* (negative weights allowed).<br><br>
* Time complexity: O(|V||E|) where V and E are the number of
* vertices and edges respectively.
*
* @example
*
* var BellmanFord =
* require('path-to-algorithms/src/graphs/shortest-path/bellman-ford');
* var Edge = BellmanFord.Edge;
* var bellmanFord = BellmanFord.bellmanFord;
* var edges = [];
* var vertexes = [
* new Vertex(0),
* new Vertex(1),
* new Vertex(2),
* new Vertex(3),
* new Vertex(4)
* ];
*
* edges.push(new Edge(0, 1, -1));
* edges.push(new Edge(0, 2, 4));
* edges.push(new Edge(1, 2, 3));
* edges.push(new Edge(1, 3, 2));
* edges.push(new Edge(3, 1, 1));
* edges.push(new Edge(4, 3, -3));
* edges.push(new Edge(1, 4, 2));
* edges.push(new Edge(3, 2, 5));
*
* // {
* // parents: { '0': null, '1': 0, '2': 1, '3': 4, '4': 1 },
* // distances: { '0': 0, '1': -1, '2': 2, '3': -2, '4': 1 }
* // }
* var pathInfo = bellmanFord(vertexes, edges, 0);
*
* @module graphs/shortest-path/bellman-ford
*/
(function (exports) {
'use strict';
exports.Vertex = require('../../data-structures/vertex').Vertex;
exports.Edge = require('../../data-structures/edge').Edge;
/**
* Computes shortest paths from a single source
* vertex to all of the other vertices.
*
* @public
* @param {Array} vertexes Vertices of the graph.
* @param {Array} edges Edges of the graph.
* @param {Number} source Start vertex.
* @returns {Object} Object with two arrays (parents and distances)
* with shortest-path information or undefined if the graph
* has a negative cycle.
*/
exports.bellmanFord = function (vertexes, edges, source) {
var distances = {};
var parents = {};
var c;
if (source) {
for (var i = 0; i < vertexes.length; i += 1) {
distances[vertexes[i].id] = Infinity;
parents[vertexes[i].id] = null;
}
distances[source.id] = 0;
for (i = 0; i < vertexes.length - 1; i += 1) {
for (var j = 0; j < edges.length; j += 1) {
c = edges[j];
if (distances[c.from.id] + c.distance < distances[c.to.id]) {
distances[c.to.id] = distances[c.from.id] + c.distance;
parents[c.to.id] = c.from.id;
}
}
}
for (i = 0; i < edges.length; i += 1) {
c = edges[i];
if (distances[c.from.id] + c.distance < distances[c.to.id]) {
return undefined;
}
}
}
return { parents: parents, distances: distances };
};
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/graphs/shortest-path/dijkstra.js
================================================
(function (exports) {
'use strict';
var dijkstra = (function () {
var Heap = require('../../data-structures/heap.js').Heap;
var current;
var visited;
var distance;
var unvisited;
/**
* Creates a new node instance.
*
* @constructor
* @private
* @param {Number} id Id of the node.
* @param {Number} distance Distance from the beginning.
*/
function Node(id, distance) {
this.node = id;
this.distance = distance;
}
/**
* Compares the distances between two nodes.
*
* @private
* @param {Node} a 1st node.
* @param {Node} b 2nd node.
* @returns {number} diff between node distances.
*/
function compareNodesDistance(a, b) {
return b.distance - a.distance;
}
/**
* Initialize all variables used for the algorithm.
*
* @private
* @param {number} src Start node.
* @param {Array} graph A distance matrix of the graph.
*/
function init(src, graph) {
var currentTemp;
current = {};
visited = [];
distance = [];
unvisited = new Heap(compareNodesDistance);
for (var i = 0; i < graph.length; i += 1) {
currentTemp = new Node();
if (src === i) {
currentTemp.distance = 0;
} else {
currentTemp.distance = Infinity;
}
currentTemp.node = i;
visited[i] = false;
distance[i] = currentTemp;
unvisited.add(currentTemp);
}
current.node = src;
current.distance = 0;
}
/**
* Dijkstra's shortest path algorithm. Finds the minimum
* distance between two given nodes using a distance matrix.<br><br>
* For the implementation is not used the most suitable data structure
* (Fibonacci heap) but the Binary heap gives also good results.<br><br>
*
* Time complexity: O(|E|+|V|log(|V|)) where V and E are the number of
* vertices and edges respectively.
*
* @public
* @module graphs/shortest-path/dijkstra
* @param {Number} src Source node.
* @param {Number} dest Destination node.
* @param {Array} graph A distance matrix of the graph.
* @returns {Number} The shortest distance between two nodes.
*
* @example
* var dijkstra =
* require('path-to-algorithms/src/graphs/shortest-path/dijkstra').dijkstra;
* var distMatrix =
* [[Infinity, 7, 9, Infinity, Infinity, 16],
* [7, Infinity, 10, 15, Infinity, Infinity],
* [9, 10, Infinity, 11, Infinity, 2],
* [Infinity, 15, 11, Infinity, 6, Infinity],
* [Infinity, Infinity, Infinity, 6, Infinity, 9],
* [16, Infinity, 2, Infinity, 9, Infinity]];
* var shortestDist = dijkstra(0, 2, distMatrix); // 9
*/
return function (src, dest, graph) {
var tempDistance = 0;
init(src, graph);
while (current.node !== dest && isFinite(current.distance)) {
for (var i = 0; i < graph.length; i += 1) {
if (current.node !== i && //if it's not the current node
!visited[i] && //and if we haven't visited this node
//and this node is sibling of the current...
Number.isFinite(graph[i][current.node])) {
tempDistance = current.distance + graph[i][current.node];
if (tempDistance < distance[i].distance) {
distance[i].distance = tempDistance;
unvisited.update(current);
}
}
}
visited[current.node] = true;
current = unvisited.extract();
}
if (distance[dest]) {
return distance[dest].distance;
}
return Infinity;
};
})();
exports.dijkstra = dijkstra;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/graphs/shortest-path/floyd-warshall.js
================================================
(function (exports) {
'use strict';
var floydWarshall = (function () {
/**
* Matrix used for the algorithm.
*/
var dist;
/**
* Initialize the distance matrix.
*
* @private
* @param {Array} graph Distance matrix of the array.
* @return {Array} Distance matrix used for the algorithm.
*/
function init(graph) {
var dist = [];
var size = graph.length;
for (var i = 0; i < size; i += 1) {
dist[i] = [];
for (var j = 0; j < size; j += 1) {
if (i === j) {
dist[i][j] = 0;
} else if (!isFinite(graph[i][j])) {
dist[i][j] = Infinity;
} else {
dist[i][j] = graph[i][j];
}
}
}
return dist;
}
/**
* Floyd-Warshall algorithm. Finds the shortest path between
* each two vertices.<br><br>
* Complexity: O(|V|^3) where V is the number of vertices.
*
* @public
* @module graphs/shortest-path/floyd-warshall
* @param {Array} graph A distance matrix of the graph.
* @return {Array} Array which contains the shortest
* distance between each two vertices.
*
* @example
* var floydWarshall =
* require('path-to-algorithms/src/graphs/shortest-path/floyd-warshall').floydWarshall;
* var distMatrix =
* [[Infinity, 7, 9, Infinity, Infinity, 16],
* [7, Infinity, 10, 15, Infinity, Infinity],
* [9, 10, Infinity, 11, Infinity, 2],
* [Infinity, 15, 11, Infinity, 6, Infinity],
* [Infinity, Infinity, Infinity, 6, Infinity, 9],
* [16, Infinity, 2, Infinity, 9, Infinity]];
*
* // [ [ 0, 7, 9, 20, 20, 11 ],
* // [ 7, 0, 10, 15, 21, 12 ],
* // [ 9, 10, 0, 11, 11, 2 ],
* // [ 20, 15, 11, 0, 6, 13 ],
* // [ 20, 21, 11, 6, 0, 9 ],
* // [ 11, 12, 2, 13, 9, 0 ] ]
* var shortestDists = floydWarshall(distMatrix);
*/
return function (graph) {
dist = init(graph);
var size = graph.length;
for (var k = 0; k < size; k += 1) {
for (var i = 0; i < size; i += 1) {
for (var j = 0; j < size; j += 1) {
if (dist[i][j] > dist[i][k] + dist[k][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
return dist;
};
}());
exports.floydWarshall = floydWarshall;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/graphs/spanning-trees/kruskal.js
================================================
// Kruskal's algorithm for minimal spanning tree implemented with the UnionFind datastructure.
(function(exports) {
'use strict';
var QuickUnion = require('../../sets/quickunion').QuickUnion;
var mergeSort = require('../../sorting/mergesort').mergeSort;
exports.Vertex = require('../../data-structures/vertex').Vertex;
exports.Edge = require('../../data-structures/edge').Edge;
exports.Graph = function (edges) {
this.edges = edges || [];
}
exports.Graph.prototype.kruskal = (function () {
var qunion;
var spanningTree;
var indexes;
/**
* Used for sorting the edges
*
* @private
* @param {Vertex} a First operand of the comparison.
* @param {Vertex} b Second operand of the comparison.
* @return {number} Number which which is equal, greater or
* less then zero and indicates whether the first vertex is
* "smaller" than the second.
*/
function compareEdges(a, b) {
return a.distance - b.distance;
}
/**
* Initialize the algorithm.
*
* @private
*/
function init() {
var edge;
var i = 0;
mergeSort(this.edges, compareEdges);
spanningTree = [];
indexes = {};
// Create links from vertices to QuickUnion elements
for (edge of this.edges) {
if (!(edge.from.id in indexes)) {
indexes[edge.from.id] = i;
i += 1;
}
if (!(edge.to.id in indexes)) {
indexes[edge.to.id] = i;
i += 1;
}
}
qunion = new QuickUnion(i);
}
return function () {
init.call(this);
var edge;
for (edge of this.edges) {
var from = indexes[edge.from.id];
var to = indexes[edge.to.id];
if (!qunion.connected(from, to)) {
qunion.union(from, to);
spanningTree.push(edge);
}
}
return new exports.Graph(spanningTree);
}
})();
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/graphs/spanning-trees/prim.js
================================================
/**
* Prim's algorithm is a greedy algorithm that finds a minimum
* spanning tree for a connected weighted undirected graph.
*
* @example
*
* var Prim = require('path-to-algorithms/src/graphs/spanning-trees/prim');
* var Graph = Prim.Graph;
* var Edge = Prim.Edge;
* var Vertex = Prim.Vertex;
*
* var graph, edges = [];
* edges.push(new Edge(new Vertex(0), new Vertex(1), 4));
* edges.push(new Edge(new Vertex(0), new Vertex(7), 8));
* edges.push(new Edge(new Vertex(1), new Vertex(7), 11));
* edges.push(new Edge(new Vertex(1), new Vertex(2), 8));
* edges.push(new Edge(new Vertex(2), new Vertex(8), 2));
* edges.push(new Edge(new Vertex(2), new Vertex(3), 7));
* edges.push(new Edge(new Vertex(2), new Vertex(5), 4));
* edges.push(new Edge(new Vertex(2), new Vertex(3), 7));
* edges.push(new Edge(new Vertex(3), new Vertex(4), 9));
* edges.push(new Edge(new Vertex(3), new Vertex(5), 14));
* edges.push(new Edge(new Vertex(4), new Vertex(5), 10));
* edges.push(new Edge(new Vertex(5), new Vertex(6), 2));
* edges.push(new Edge(new Vertex(6), new Vertex(8), 6));
* edges.push(new Edge(new Vertex(8), new Vertex(7), 7));
* graph = new Graph(edges, edges.length);
*
* // { edges:
* // [ { e: '1', v: 0, distance: 4 },
* // { e: '2', v: 8, distance: 2 },
* // { e: '3', v: 2, distance: 7 },
* // { e: '4', v: 3, distance: 9 },
* // { e: '5', v: 2, distance: 4 },
* // { e: '6', v: 5, distance: 2 },
* // { e: '7', v: 0, distance: 8 },
* // { e: '8', v: 7, distance: 7 } ],
* // nodesCount: 0 }
* var spanningTree = graph.prim();
*
* @module graphs/spanning-trees/prim
*/
(function (exports) {
'use strict';
var Heap = require('../../data-structures/heap').Heap;
exports.Vertex = require('../../data-structures/vertex').Vertex;
exports.Edge = require('../../data-structures/edge').Edge;
/**
* Graph.
*
* @constructor
* @public
* @param {Array} edges Array with graph edges.
* @param {Number} nodesCount Number of nodes in graph.
*/
exports.Graph = function (edges, nodesCount) {
this.edges = edges || [];
this.nodesCount = nodesCount || 0;
};
/**
* Executes Prim's algorithm and returns minimum spanning tree.
*
* @public
* @method
* @return {Graph} Graph which is the minimum spanning tree.
*/
exports.Graph.prototype.prim = (function () {
var queue;
/**
* Used for comparitions in the heap
*
* @private
* @param {Vertex} a First operand of the comparition.
* @param {Vertex} b Second operand of the comparition.
* @return {number} Number which which is equal, greater or
* less then zero and indicates whether the first vertex is
* "greater" than the second.
*/
function compareEdges(a, b) {
return b.distance - a.distance;
}
/**
* Initialize the algorithm.
*
* @private
*/
function init() {
queue = new Heap(compareEdges);
}
return function () {
init.call(this);
var inTheTree = {};
var startVertex = this.edges[0].e.id;
var spannigTree = [];
var parents = {};
var distances = {};
var current;
inTheTree[startVertex] = true;
queue.add({
node: startVertex,
distance: 0
});
const process = function (e) {
if (inTheTree[e.v.id] && inTheTree[e.e.id]) {
return;
}
var collection = queue.getCollection();
var node;
if (e.e.id === current) {
node = e.v.id;
} else if (e.v.id === current) {
node = e.e.id;
} else {
return;
}
for (var i = 0; i < collection.length; i += 1) {
if (collection[i].node === node) {
if (collection[i].distance > e.distance) {
queue.changeKey(i, {
node: node,
distance: e.distance
});
parents[node] = current;
distances[node] = e.distance;
}
return;
}
}
queue.add({
node: node,
distance: e.distance
});
parents[node] = current;
distances[node] = e.distance;
};
for (var i = 0; i < this.nodesCount - 1; i += 1) {
current = queue.extract().node;
inTheTree[current] = true;
this.edges.forEach(process);
}
for (var node in parents) {
spannigTree.push(
new exports.Edge(node, parents[node], distances[node]));
}
return new exports.Graph(spannigTree);
};
}());
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/others/fibonacci.js
================================================
/**
* Nth number of fibonacci's sequence
*
* Returns the nth number of fibonacci's sequence.
*
* @public
*
* @example
* var fibonacci = require('path-to-algorithms/src/others/fibonacci').fibonacci;
* var nth = fibonacci(20);
*
* console.log(nth); // 6765
*
* @param {Number} n The nth position in fibonacci's sequence
*
* @module others/fibonacci
*/
(function (exports) {
'use strict';
function fibonacci(n) {
if (n > 97) {
throw 'Input too large, results in inaccurate fibonacci value.';
}
var n1 = 0;
var n2 = 1;
var aux;
while (n > 0) {
aux = n1;
n1 = n2;
n2 += aux;
n = n - 1;
}
return n1;
}
exports.fibonacci = fibonacci;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/others/fibonacciMemory.js
================================================
/**
* Nth number of fibonacciMemory's sequence
*
* Returns the nth number of fibonacciMemory's sequence.
*
* @public
*
* @example
* var fibonacciMemory = require('path-to-algorithms/src/others/fibonacciMemory').fibonacciMemory;
* var nth = fibonacciMemory(20);
*
* console.log(nth); // 6765
*
* @param {Number} n The nth position in fibonacciMemory's sequence
*
* @module others/fibonacciMemory
*/
(function (exports) {
'use strict';
function fibonacciMemory(n) {
var i = 0;
var aux = [0, 1];
while (n !== i) {
aux[i + 2] = aux[i] + aux[i + 1];
i += 1;
}
return aux[i];
}
exports.fibonacciMemory = fibonacciMemory;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/others/hanoi.js
================================================
(function (exports) {
'use strict';
/**
* Returns all movements needed to solve Hanoi Tower problem.
*
* @public
* @module others/hanoi
*
* @example
*
* var hanoi = require('path-to-algorithms/src/others/hanoi').hanoi;
* var movements = hanoi(3, 'a', 'b', 'c');
*
* // Move a to c
* // Move a to b
* // Move c to b
* // Move a to c
* // Move b to a
* // Move b to c
* // Move a to c
* movements.forEach(function (move) {
* console.log('Move', move[0], 'to', move[1]);
* });
*
* @param {Number} count Count of the plates/stones.
* @param {String|Number} source Identifier of the 1st peg.
* @param {String|Number} intermediate Identifier of the 2nd peg.
* @param {String|Number} goal Identifier of the 3rd peg.
* @return Array which contains all the moves required
* in order to place all the plates onto the last peg.
*/
function hanoi(count, source, intermediate, goal, result) {
result = result || [];
if (count === 1) {
result.push([source, goal]);
} else {
hanoi(count - 1, source, goal, intermediate, result);
result.push([source, goal]);
hanoi(count - 1, intermediate, source, goal, result);
}
return result;
}
exports.hanoi = hanoi;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/others/levenshtein-distance.js
================================================
(function (exports) {
'use strict';
var levenshteinDistance = (function () {
function levenshteinDistance (s, ls, t, lt) {
var memo = [];
var currRowMemo;
var i;
var k;
for (k = 0; k <= lt; k += 1) {
memo[k] = k;
}
for (i = 1; i <= ls; i += 1) {
currRowMemo = [i];
for (k = 1; k <= lt; k += 1) {
currRowMemo[k] = Math.min(
currRowMemo[k - 1] + 1,
memo[k] + 1,
memo[k - 1] + (s[i - 1] !== t[k - 1] ? 1 : 0)
);
}
memo = currRowMemo;
}
return memo[lt];
}
/**
* The Levenshtein distance between two strings is a minimum number
* of edits needed to transform one string into the other, with the
* allowable edit operations being insertion, deletion,
* or substitution of a single character.
*
* @public
* @module others/levenshtein-distance
*
* @example
*
* var dist = require('path-to-algorithms/src/others/' +
* 'levenshtein-distance').levenshteinDistance;
* console.log(dist('kitten', 'sitting')); // 3
*
* @param {String} s Source string.
* @param {String} t Target string.
* @return {Number} Minimum number of edits needed
* to transform source string into the target string.
*/
return function (s, t) {
return levenshteinDistance(s, s.length, t, t.length);
};
}());
exports.levenshteinDistance = levenshteinDistance;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/others/min-coins-change.js
================================================
(function (exports) {
'use strict';
/**
* Returns the minimum number of coins from given set,
* which sum equals to given change. This is famous
* problem from the dynamic programming:
* {@link https://en.wikipedia.org/wiki/Change-making_problem}
*
* @public
* @module others/minCoinsChange
*
* @example
*
* var minCoinsChange =
* require('path-to-algorithms/src/others/min-coins-change')
* .minCoinsChange;
* var coins = minCoinsChange([1, 2, 3], 5); // [ 2, 3 ]
*
* @param {Array} coins The sorted list of the coins used for the change.
* @param {Number} change The change, which should be returned.
* @return Array which contains the minimum coins from the given
* list, required for the change.
*/
function minCoinsChange(coins, change) {
var minChange = [[0]];
if (coins.indexOf(change) >= 0) {
return [change];
}
for (var i = 1; i <= change; i += 1) {
for (var j = 0; j < coins.length && coins[j] <= change; j += 1) {
for (var k = 0; k < minChange.length; k += 1) {
if (k + coins[j] === i) {
minChange[i] = minChange[k].concat([coins[j]]);
}
}
}
}
var result = minChange[change];
if (!result) {
return undefined;
}
return result.slice(1);
}
exports.minCoinsChange = minCoinsChange;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/others/minimax.js
================================================
(function (exports) {
'use strict';
/* eslint max-params: 0 */
/**
* @param {Function} getPossibleNextStatesFn Function which returns all possible next moves with states .
* @param {Function} isGameOverFn Function which returns if game is over.
* @param {Function} getScoreFn Function which returns score.
* @return {Function} minimax function
*/
function minimaxBuilder(
getPossibleNextStatesFn,
isGameOverFn,
getScoreFn
) {
/**
* Minimax (sometimes MinMax, MM[1] or saddle point[2]) is a decision rule used in artificial intelligence,
* decision theory, game theory, statistics, and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario.
* Optimized with alpha-beta pruning.
* {@link https://en.wikipedia.org/wiki/Minimax}
* {@link https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning}
*
* @public
* @module others/minimax
*
* @example
*
* var miniMax =
* require('path-to-algorithms/src/others/minimax').minimax;
* var result = minimax(
* [1, 2, 3],
* true,
* 5,
* -Infinity,
* Infinity,
* state => ({ move: 0, state: [2, 3, 4] }),
* state => state[1] < 3,
* state => state[1]
* );
*
* @param {*} state Current game state
* @param {Boolean} maximize Defines if the result should be maximized or minimized
* @param {Number} depth Defines the maximum depth search
* @param {Number} alpha Maximum score that the minimizing player is assured
* @param {Number} beta Minimum score that the maximizing player is assured
* @return {{score: Number, move: *}} which contains the minimum coins from the given
* list, required for the change.
*/
const minimax = (
state,
maximize,
depth,
alpha,
beta
) => {
if (depth === 0 || isGameOverFn(state)) {
const score = getScoreFn(state);
return {score, move: null};
}
const possibleMoveResults = getPossibleNextStatesFn(state);
if (maximize) {
let maxResult = {score: -Infinity, move: null};
for (const next of possibleMoveResults) {
const result = minimax(
next.state,
false,
depth - 1,
alpha,
beta
);
if (result.score > maxResult.score) {
maxResult = {score: result.score, move: next.move};
}
alpha = Math.max(alpha, result.score);
if (alpha >= beta) {
break;
}
}
return maxResult;
} else {
let minResult = {score: Infinity, move: null};
for (const next of possibleMoveResults) {
const result = minimax(
next.state,
true,
depth - 1,
alpha,
beta
);
if (result.score < minResult.score) {
minResult = {score: result.score, move: next.move};
}
beta = Math.min(beta, result.score);
if (beta <= alpha) {
break;
}
}
return minResult;
}
}
return minimax;
}
exports.minimaxBuilder = minimaxBuilder;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/others/minkowski-distance.js
================================================
(function (exports) {
'use strict';
var minkowskiDistance = (function () {
function chebyshevDistance (x, y, lx, p, mathfn) {
var ret = -p;
var i;
for (i = 0; i < lx; i += 1) {
ret = mathfn(ret, Math.abs(x[i] - y[i]));
}
return ret;
}
function minkowskiDistance (x, lx, y, ly, p) {
var d;
var i;
if (lx !== ly) {
throw 'Both vectors should have same dimension';
}
if (isNaN(p)) {
throw 'The order "p" must be a number';
}
if (p === Number.POSITIVE_INFINITY) {
return chebyshevDistance(x, y, lx, p, Math.max);
} else if (p === Number.NEGATIVE_INFINITY) {
return chebyshevDistance(x, y, lx, p, Math.min);
} else if (p < 1) {
throw 'Order less than 1 will violate the triangle inequality';
} else {
d = 0;
for (i = 0; i < lx; i += 1) {
d += Math.pow(Math.abs(x[i] - y[i]), p);
}
return isNaN(d)
? 0
: Math.pow(d, 1 / p);
}
}
/**
* The Minkowski distance between two points gets generalized
* metric distance
* when p === 1, this becomes same as Manhattan Distance
* when p === 2, this becomes same as Euclidean Distance
* when p === Positive or Negative Infinity,
* this becomes chebyshev distance
*
* @public
* @module others/minkowski-distance
*
* @example
* var dist = require('path-to-algorithms/src/others/' +
* 'minkowski-distance').minkowskiDistance;
* console.log(dist([0, 1], [1, 1], 2)); // 1
*
* @param {Array} x source point
* @param {Array} y target point
* @param {Number} p order of Minkowski distance
* @returns {Number} distance between two points, if distance
* is NaN, then this returns 0
*/
return function (x, y, p) {
return minkowskiDistance (x, x.length, y, y.length, p);
};
}());
exports.minkowskiDistance = minkowskiDistance;
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/primes/is-prime.js
================================================
(function (exports) {
'use strict';
/**
* Advanced (optimised) method for checking if provided number is prime.
* For example for number 104743 it should return true, for 104744 - false.
*
* @module primes/is-prime
* @param {Number} number - Number that we check on prime.
* @returns {Boolean} Will return true if provided number is prime.
*
* @example
* var isPrime = require('path-to-algorithms/src/is-prime').isPrime;
*
* console.log(isPrime(7)); // true
* console.log(isPrime(18)); // false
*/
exports.isPrime = function (number) {
if (number < 2) {
return false;
}
if (number % 2 === 0) {
return (number === 2);
}
if (number % 3 === 0) {
return (number === 3);
}
var horizon = Math.floor(Math.sqrt(number));
var factor = 5;
while (factor <= horizon) {
if (number % factor === 0) {
return false;
}
if (number % (factor + 2) === 0) {
return false;
}
factor += 6;
}
return true;
};
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/primes/prime-factor-tree.js
================================================
(function (exports) {
'use strict';
/**
* Method will return list of all primes for provided number.
* For example for number 18 it should return following list of primes
* [2, 3, 3].
*
* @module primes/prime-factor-tree
* @param {Number} number - Number for which method will find all primes.
* @returns {Array} List of available primes for provided number.
*
* @example
* var primeFactorTree = require('path-to-algorithms/src/prime-factor-tree')
* .primeFactorTree;
*
* console.log(primeFactorTree(18)); // [2, 3, 3]
* console.log(primeFactorTree(600851475143)); // [71, 839, 1471, 6857]
*/
exports.primeFactorTree = function (number) {
var array = [];
var s = 6;
while (number > 1 && number % 2 === 0) {
number /= 2;
array.push(2);
}
while (number > 2 && number % 3 === 0) {
number /= 3;
array.push(3);
}
while (number > 4) {
var p = s - 1;
var q = s + 1;
while (number > 4 && number % p === 0) {
number /= p;
array.push(p);
}
while (number > 4 && number % q === 0) {
number /= q;
array.push(q);
}
s += 6;
}
return array;
};
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/primes/sieve-of-atkins.js
================================================
(function (exports) {
'use strict';
/**
* Sieve of Atkins.
*
* Modern algorithm for finding all prime numbers up to a specified integer.
*
* Returns list of primes up to specified limit.
*
* For example, for limit 10 it should return following list of primes:
* [2, 3, 5, 7].
*
* @module primes/sieve-of-atkins
* @param {Number} limit - Algorithm will returns list of primes up to
* specified limit.
* @returns {Array} Will return list with all prime numbers up to provided.
* limit.
*
* @example
* var sieveOfAtkins =
* require('path-to-algorithms/src/sieve-of-atkins').sieveOfAtkins;
*
* console.log(sieveOfAtkins(12)); // [2, 3, 5, 7, 11]
*/
exports.sieveOfAtkins = function (limit) {
if (limit <= 1) {
return [];
}
const sieve = Array(limit + 1);
const testingLimit = Math.ceil(Math.sqrt(limit));
var i;
var j;
var n;
for (i = 1; i < testingLimit; i += 1) {
var ii = i * i;
for (j = 1; j < testingLimit; j += 1) {
var jj = j * j;
if (ii + jj >= limit) {
break;
}
n = 4 * ii + jj;
if (n <= limit && (n % 12 === 1 || n % 12 === 5)) {
sieve[n] = !sieve[n];
}
n = 3 * ii + jj;
if (n <= limit && (n % 12 === 7)) {
sieve[n] = !sieve[n];
}
n = 3 * ii - jj;
if (i > j && n <= limit && (n % 12 === 11)) {
sieve[n] = !sieve[n];
}
}
}
for (n = 5; n <= testingLimit; n += 1) {
if (sieve[n]) {
j = n * n;
for (i = j; i <= limit; i += j) {
sieve[i] = false;
}
}
}
const primes = [2];
if (limit > 2) {
primes.push(3);
}
sieve.forEach(function (value, key) {
if (value) {
this.push(key);
}
}, primes);
return primes;
}
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/primes/sieve-of-eratosthenes.js
================================================
(function (exports) {
'use strict';
/**
* Sieve of Eratosthenes.
*
* Simple, ancient algorithm for finding all prime numbers up to given limit.
*
* Returns list of primes up to specified limit.
*
* For example, for limit 10 it should return following list of primes:
* [2, 3, 5, 7].
*
* @module primes/sieve-of-eratosthenes
* @param {Number} limit - Algorithm will returns list of primes up to
* specified limit.
* @returns {Array} Will return list with all prime numbers up to provided.
* limit.
*
* @example
* var sieveOfEratosthenes =
* require('path-to-algorithms/src/sieve-of-eratosthenes').sieveOfEratosthenes;
*
* console.log(sieveOfEratosthenes(12)); // [2, 3, 5, 7, 11]
*/
exports.sieveOfEratosthenes = function (limit) {
var sieve = [];
var primes = [];
var k;
var l;
sieve[1] = false;
for (k = 2; k <= limit; k += 1) {
sieve[k] = true;
}
for (k = 2; k * k <= limit; k += 1) {
if (sieve[k] !== true) {
continue;
}
for (l = k * k; l <= limit; l += k) {
sieve[l] = false;
}
}
sieve.forEach(function (value, key) {
if (value) {
this.push(key);
}
}, primes);
return primes;
};
}(typeof exports === 'undefined' ? window : exports));
================================================
FILE: src/searching/binarysearch.js
================================================
(function (exports) {
'use strict';
function id (val) { return val; }
function get (key) { return function (val) { return val[key]; }; }
/**
* Searches for specific element in a given array using
* the binary search algorithm.<br><br>
* Time complexity: O(log N).
*
* @example
*
* var search = require('path-to-algorithms/src/searching/'+
* 'binarysearch').binarySearch;
* console.log(search([1, 2, 3, 4, 5], 4)); // 3
*
* @public
* @module searching/binarysearch
* @param {Array} array Input array.
* @param {Number} value Value of the element which index should be found.
* @returns {Number} Index of the element or -1 if not found.
*/
function binarySearch(array, value, key) {
key = !key ? id : typeof key === 'string' ? get(key) : key;
value = key(value);
var middle = Math.floor(array.length / 2);
var left = 0;
var right = array.length;
while (right >= left) {
var middleValue = key(array[middle]);
if (middleValue === value) {
return middle;
} else if (middleValue > value) {
right = middle - 1;
} else {
left = middle + 1;
}
middle = Math.floor((left + right) / 2);
}
return -1;
}
exports.binarySearch = binarySearch;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/searching/interpolation-search.js
================================================
(function(exports) {
'use strict';
/**
* Searches for specific element in a given array using
* the interpolation search algorithm.<br><br>
* Time complexity: O(log log N) when elements are uniformly
* distributed, and O(N) in the worst case
*
* @example
*
* var search = require('path-to-algorithms/src/searching/'+
* 'interpolation-search').interpolationSearch;
* console.log(search([1, 2, 3, 4, 5], 4)); // 3
*
* @public
* @module searching/interpolation-search
* @param {Array} sortedArray Input array.
* @param {Number} seekIndex of the element which index should be found.
* @returns {Number} Index of the element or -1 if not found.
*/
function interpolationSearch(sortedArray, seekIndex) {
let leftIndex = 0;
let rightIndex = sortedArray.length - 1;
while (leftIndex <= rightIndex) {
const rangeDiff = sortedArray[rightIndex] - sortedArray[leftIndex];
const indexDiff = rightIndex - leftIndex;
const valueDiff = seekIndex - sortedArray[leftIndex];
if (valueDiff < 0) {
return -1;
}
if (!rangeDiff) {
return sortedArray[leftIndex] === seekIndex ? leftIndex : -1;
}
const middleIndex =
leftIndex + Math.floor((valueDiff * indexDiff) / rangeDiff);
if (sortedArray[middleIndex] === seekIndex) {
return middleIndex;
}
if (sortedArray[middleIndex] < seekIndex) {
leftIndex = middleIndex + 1;
} else {
rightIndex = middleIndex - 1;
}
}
return -1;
}
exports.interpolationSearch = interpolationSearch;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/searching/jump-search.js
================================================
(function(exports) {
'use strict';
/**
* Searches for specific element in a given array using
* the jump search algorithm.<br><br>
* Time complexity: O(log N).
*
* @example
*
* var search = require('path-to-algorithms/src/searching/'+
* 'jump-search').jumpSearch;
* console.log(search([1, 2, 3, 4, 5], 4)); // 3
*
* @public
* @module searching/jumpsearch
* @param {Array} sortedArray Input array.
* @param {Number} seekIndex of the element which index should be found.
* @returns {Number} Index of the element or -1 if not found.
*/
function jumpSearch(sortedArray, seekIndex) {
// exit if array empty
const arrayLength = sortedArray.length;
if (!arrayLength) {
return -1;
}
// set jumpSize
const jumpSize = Math.floor(Math.sqrt(arrayLength));
let blockStart = 0;
let blockEnd = jumpSize;
while (seekIndex > sortedArray[Math.min(blockEnd, arrayLength) - 1]) {
blockStart = blockEnd;
blockEnd += jumpSize;
// if out of array bounds exit
if (blockStart > arrayLength) {
return -1;
}
}
let currentIndex = blockStart;
while (currentIndex < Math.min(blockEnd, arrayLength)) {
if (sortedArray[currentIndex] === seekIndex) {
return currentIndex;
}
currentIndex += 1;
}
return -1;
}
exports.jumpSearch = jumpSearch;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/searching/knuth-morris-pratt.js
================================================
(function (exports) {
'use strict';
var kmp = (function () {
function builtKMPTable(str) {
var res = [];
var len;
var front;
var end;
var found;
for (var i = 1; i <= str.length; i += 1) {
front = Math.max(1, i - ((res[i - 2] || 0) + 1));
end = Math.min(i - 1, (res[i - 2] || 0) + 1);
found = false;
len = 0;
while (end >= 1 && front <= i && !found) {
if (str.substring(0, end) === str.substring(front, i)) {
found = true;
len = end;
} else {
end -= 1;
front += 1;
}
}
res[i - 1] = len;
}
return res;
}
/**
* Knuth–Morris–Pratt algorithm. Searches for the position of
* the first occurrence of a specified value in a string.
*
* @example
*
* var indexOf = require('path-to-algorithm/src/searching/'+
* 'knuth-morris-pratt').kmp;
* console.log(indexOf('hello', 'll')); // 2
*
* @public
* @module searching/knuth-morris-pratt
* @param {String} str String.
* @param {String} substr Substring.
* @return {Number} A Number, representing the position
* where the specified substring occurs for the first
* time, or -1 if it never occurs.
*/
function indexOf(str, substr) {
if (str === substr) {
return 0;
}
var table = builtKMPTable(substr);
var i = 0;
var j = 0;
while (i < str.length) {
if (str[i] === substr[j]) {
i += 1;
j += 1;
}
if (j === substr.length) {
return i - j;
}
if (i < str.length && str[i] !== substr[j]) {
if (j > 0 && table[j - 1] !== 0) {
j = table[j - 1];
} else {
i += 1;
j = 0;
}
}
}
return -1;
}
return indexOf;
}());
exports.kmp = kmp;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/searching/linearSearch.js
================================================
(function (exports) {
'use strict';
/**
* Searches for specific element in a given array
* using the linear search algorithm
* Time complexity: O(n)
*
* @param {Array} array Input array
* @param {Number} key the number whose index is to be found
* @returns {Number} the index of the first instance of number or else -1 if not found
*/
const linearSearch = (array, key) => {
for (let i = 0; i < array.length; i += 1) {
if (array[i] === key) {
return i;
}
}
return -1;
};
exports.linearSearch = linearSearch;
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/searching/longest-common-subsequence.js
================================================
(function (exports) {
'use strict';
exports.longestCommonSubsequence = (function () {
/**
* Find the lengths of longest common sub-sequences
* of two strings and their substrings.
*
* Complexity: O(MN).
*
* @private
* @param {String} first string
* @param {String} second string
* @return {Array} two dimensional array with LCS
* lengths of input strings and their substrings.
*
*/
function getLcsLengths(str1, str2) {
var result = [];
for (var i = -1; i < str1.length; i = i + 1) {
result[i] = [];
for (var j = -1; j < str2.length; j = j + 1) {
if (i === -1 || j === -1) {
result[i][j] = 0;
} else if (str1[i] === str2[j]) {
result[i][j] = result[i - 1][j - 1] + 1;
} else {
result[i][j] = Math.max(result[i - 1][j], result[i][j - 1]);
}
}
}
return result;
}
/**
* Find longest common sub-sequences of two strings.
*
* Complexity: O(M + N).
*
* @private
* @param {String} first string
* @param {String} second string
* @return {Array} two dimensional array with LCS
* lengths of input strings and their substrings
* returned from 'getLcsLengths' function.
*
*/
function getLcs(str1, str2, lcsLengthsMatrix) {
var execute = function (i, j) {
if (!lcsLengthsMatrix[i][j]) {
return '';
} else if (str1[i] === str2[j]) {
return execute(i - 1, j - 1) + str1[i];
} else if (lcsLengthsMatrix[i][j - 1] > lcsLengthsMatrix[i - 1][j]) {
return execute(i, j - 1);
} else {
return execute(i - 1, j);
}
};
return execute(str1.length - 1, str2.length - 1);
}
/**
* Algorithm from dynamic programming. It finds the longest
* common sub-sequence of two strings. For example for strings 'abcd'
* and 'axxcda' the longest common sub-sequence is 'acd'.
*
* @example
* var subsequence = require('path-to-algorithms/src/searching/'+
* 'longest-common-subsequence').longestCommonSubsequence;
* console.log(subsequence('abcd', 'axxcda'); // 'acd'
*
* @public
* @module searching/longest-common-subsequence
* @param {String} first input string.
* @param {String} second input string.
* @return {Array} Longest common subsequence.
*/
return function (str1, str2) {
var lcsLengthsMatrix = getLcsLengths(str1, str2);
return getLcs(str1, str2, lcsLengthsMatrix);
};
})();
})(typeof window === 'undefined' ? module.exports : window);
================================================
FILE: src/searching/longest-increasing-subsequence.js
================================================
(function (exports) {
'use strict';
exports.longestIncreasingSubsequence = (function () {
/**
* Find the index of the first largest element in array.
* Complexity: O(N).
*
* @private
* @param {Array} array The array in which the largest
* element should be found.
* @return {Number} index of the first largest element
*/
function max(array) {
if (!array || !array.length) {
return -1;
}
var maxIdx = 0;
for (var i = 1; i < array.length; i += 1) {
if (array[maxIdx].distance < array[i].distance) {
maxIdx = i;
}
}
return maxIdx;
}
/**
* Default comparison method.
* @private
*/
function asc(a, b) {
return a - b;
}
/**
* Creates directed graph from given array.
* Each element's neighbours are the elements which can be
* after the element in the resulting sequence.<br><br>
* Complexity: O(N^2).
* @private
* @param {Array} array The input array.
* @param {Function} cmp Comparator.
* @return {Object} Graph represented with list of neighbours.
*/
function buildDag(array, cmp) {
var result = [];
for (var i = 0; i < array.length; i += 1) {
result[i] = [];
for (var j = i + 1; j < array.length; j += 1) {
if (cmp(array[i], array[j]) < 0) {
result[i].push(j);
}
}
}
return result;
}
/**
* Finds the longest increasing sub-sequence for given node.<br><br>
* Complexity: O(N^N).
* @private
* @param {Object} dag Graph represented with list of neighbours.
* @param {number} node The current node.
* @return {object} The longest increasing sub-sequence for given node.
*/
function find(dag, node) {
node = node || 0;
if (find.memo[node]) {
return find.memo[node];
}
var neighbours = dag[node];
var neighboursDistance = [];
var maxDist;
// var maxNode;
var distance;
var result;
if (!neighbours.length) {
return { distance: 1, neighbour: undefined, node: node };
}
for (var i = 0; i < neighbours.length; i += 1) {
neighboursDistance[i] = find(dag, neighbours[i]);
}
maxDist = max(neighboursDistance);
// maxNode = neighbours[maxDist];
distance = 1 + neighboursDistance[maxDist].distance;
find.memo[node] = result = {
distance: distance,
neighbour: neighboursDistance[maxDist],
node: node
};
return result;
}
/**
* Algorithm from dynamic programming. It finds the longest
* sub-sequence of increasing numbers. It is not required
* the numbers to be neighboring. For example for 1, 5, 2
* sequence the longest sub-sequence i
gitextract_q50stgoz/
├── .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
SYMBOL INDEX (119 symbols across 63 files)
FILE: src/combinatorics/cartesianproduct.js
function cartesianProduct (line 7) | function cartesianProduct(sets, index, current) {
FILE: src/combinatorics/combinations.js
function combinations (line 7) | function combinations(arr, k, start, idx, current) {
FILE: src/combinatorics/permutations.js
function swap (line 7) | function swap(arr, i, j) {
function permutations (line 13) | function permutations(arr, current) {
FILE: src/combinatorics/variations-repetition.js
function variations (line 7) | function variations(arr, k, index, current) {
FILE: src/compression/runlength/runlength.js
function convertToAscii (line 16) | function convertToAscii(str) {
function runLength (line 32) | function runLength(vector) {
FILE: src/data-structures/bloomfilter.js
function randomUint32 (line 16) | function randomUint32() {
function hashFnv32a (line 30) | function hashFnv32a(str, asString, seed) {
function mkHashFun (line 49) | function mkHashFun(seed, limit) {
FILE: src/data-structures/interval-tree.js
function addNode (line 77) | function addNode(node, side, interval) {
function addHelper (line 92) | function addHelper(node, interval) {
function contains (line 123) | function contains(point, node) {
function intersects (line 156) | function intersects(a, b) {
function intersectsHelper (line 161) | function intersectsHelper(interval, node) {
function heightHelper (line 192) | function heightHelper(node) {
FILE: src/data-structures/linked-list.js
function inverse (line 234) | function inverse(current, next) {
FILE: src/data-structures/red-black-tree.js
function Node (line 55) | function Node(key, value, left, right, color) {
FILE: src/data-structures/segment-tree.js
function SegmentTree (line 32) | function SegmentTree(invalidValue, aggregate) {
FILE: src/data-structures/size-balanced-tree.js
function CreateSBTreeClass (line 33) | function CreateSBTreeClass (Node, Nil, updateChild) {
FILE: src/data-structures/suffix-tree.js
function Node (line 4) | function Node(val) {
function SuffixTree (line 9) | function SuffixTree() {
function maxPrefix (line 15) | function maxPrefix(a, b) {
function addNode (line 27) | function addNode(suffix, current) {
FILE: src/graphics/bezier.js
function linearBezier (line 4) | function linearBezier(p0, p1, t) {
function quadraticBezier (line 8) | function quadraticBezier(p0, p1, p2, t) {
function cubicBezier (line 12) | function cubicBezier(p0, p1, p2, p3, t) {
FILE: src/graphics/bresenham-line-drawing.js
function drawPoint (line 9) | function drawPoint(x, y) {
function drawLine (line 22) | function drawLine(x1, y1, x2, y2, draw) {
FILE: src/graphs/others/tarjan-connected-components.js
function tarjanConnectedComponents (line 27) | function tarjanConnectedComponents(graph) {
FILE: src/graphs/others/topological-sort.js
function topologicalSortHelper (line 6) | function topologicalSortHelper(node, visited, temp, graph, result) {
FILE: src/graphs/searching/bfs.js
function buildPath (line 6) | function buildPath(parents, targetNode) {
FILE: src/graphs/searching/dfs.js
function hasPath (line 6) | function hasPath(graph, current, goal) {
FILE: src/graphs/shortest-path/dijkstra.js
function Node (line 20) | function Node(id, distance) {
function compareNodesDistance (line 33) | function compareNodesDistance(a, b) {
function init (line 44) | function init(src, graph) {
FILE: src/graphs/shortest-path/floyd-warshall.js
function init (line 18) | function init(graph) {
FILE: src/graphs/spanning-trees/kruskal.js
function compareEdges (line 30) | function compareEdges(a, b) {
function init (line 39) | function init() {
FILE: src/graphs/spanning-trees/prim.js
function compareEdges (line 84) | function compareEdges(a, b) {
function init (line 93) | function init() {
FILE: src/others/fibonacci.js
function fibonacci (line 21) | function fibonacci(n) {
FILE: src/others/fibonacciMemory.js
function fibonacciMemory (line 21) | function fibonacciMemory(n) {
FILE: src/others/hanoi.js
function hanoi (line 33) | function hanoi(count, source, intermediate, goal, result) {
FILE: src/others/levenshtein-distance.js
function levenshteinDistance (line 6) | function levenshteinDistance (s, ls, t, lt) {
FILE: src/others/min-coins-change.js
function minCoinsChange (line 25) | function minCoinsChange(coins, change) {
FILE: src/others/minimax.js
function minimaxBuilder (line 11) | function minimaxBuilder(
FILE: src/others/minkowski-distance.js
function chebyshevDistance (line 6) | function chebyshevDistance (x, y, lx, p, mathfn) {
function minkowskiDistance (line 17) | function minkowskiDistance (x, lx, y, ly, p) {
FILE: src/searching/binarysearch.js
function id (line 4) | function id (val) { return val; }
function get (line 5) | function get (key) { return function (val) { return val[key]; }; }
function binarySearch (line 24) | function binarySearch(array, value, key) {
FILE: src/searching/interpolation-search.js
function interpolationSearch (line 21) | function interpolationSearch(sortedArray, seekIndex) {
FILE: src/searching/jump-search.js
function jumpSearch (line 20) | function jumpSearch(sortedArray, seekIndex) {
FILE: src/searching/knuth-morris-pratt.js
function builtKMPTable (line 5) | function builtKMPTable(str) {
function indexOf (line 48) | function indexOf(str, substr) {
FILE: src/searching/longest-common-subsequence.js
function getLcsLengths (line 19) | function getLcsLengths(str1, str2) {
function getLcs (line 49) | function getLcs(str1, str2, lcsLengthsMatrix) {
FILE: src/searching/longest-increasing-subsequence.js
function max (line 15) | function max(array) {
function asc (line 32) | function asc(a, b) {
function buildDag (line 46) | function buildDag(array, cmp) {
function find (line 67) | function find(dag, node) {
FILE: src/searching/maximum-subarray-divide-and-conquer.js
function crossSubarray (line 14) | function crossSubarray(array, left, middle, right) {
function maxSubarrayPartitioner (line 44) | function maxSubarrayPartitioner(array, left, right) {
function maxSubarray (line 74) | function maxSubarray(array) {
FILE: src/searching/maximum-subarray.js
function maxSubarray (line 22) | function maxSubarray(array) {
FILE: src/searching/quickselect.js
function quickselect (line 24) | function quickselect(arr, n, lo, hi) {
FILE: src/searching/recursive-binarysearch.js
function recursiveBinarySearch (line 13) | function recursiveBinarySearch(array, value, left, right) {
FILE: src/shuffle/fisheryates.js
function shuffle (line 20) | function shuffle(array) {
FILE: src/shuffle/richarddurstenfeld.js
function shuffle (line 21) | function shuffle(array) {
FILE: src/sorting/3-way-string-quicksort.js
function charAt (line 6) | function charAt(str, i) {
function swap (line 10) | function swap(arr, i, j) {
function quicksort (line 16) | function quicksort(arr, lo, hi, d) {
FILE: src/sorting/bubblesort.js
function comparator (line 4) | function comparator(a, b) {
function bubbleSort (line 25) | function bubbleSort(array, cmp) {
FILE: src/sorting/bucketsort.js
function insertionSort (line 14) | function insertionSort(array) {
function createBuckets (line 38) | function createBuckets(array) {
function sortBuckets (line 58) | function sortBuckets(buckets) {
function unionBuckets (line 75) | function unionBuckets(buckets) {
FILE: src/sorting/countingsort.js
function getCount (line 13) | function getCount(array) {
function getLessCount (line 31) | function getLessCount(array) {
function sort (line 50) | function sort(array, less) {
FILE: src/sorting/heapsort.js
function comparator (line 4) | function comparator(a, b) {
function heapify (line 20) | function heapify(array, index, heapSize, cmp) {
function buildMaxHeap (line 49) | function buildMaxHeap(array, cmp) {
FILE: src/sorting/insertion-binary-sort.js
function comparator (line 4) | function comparator(a, b) {
function insertionBinarySort (line 29) | function insertionBinarySort(array, cmp) {
FILE: src/sorting/insertionsort.js
function compare (line 4) | function compare(a, b) {
function insertionSort (line 26) | function insertionSort(array, cmp) {
FILE: src/sorting/lsd.js
function lsd (line 20) | function lsd(arr, letterIdx) {
FILE: src/sorting/mergesort.js
function compare (line 9) | function compare(a, b) {
function mergeSort (line 30) | function mergeSort(array, cmp, start, end) {
FILE: src/sorting/msd.js
function charCodeAt (line 4) | function charCodeAt(str, i) {
function sort (line 8) | function sort(arr, lo, hi, d) {
function msd (line 57) | function msd(arr, d) {
FILE: src/sorting/oddeven-sort.js
function oddEvenSort (line 18) | function oddEvenSort(arr) {
FILE: src/sorting/quicksort-declarative.js
function compare (line 5) | function compare(a, b) {
function quicksort (line 24) | function quicksort(array, cmp) {
FILE: src/sorting/quicksort-middle.js
function compare (line 5) | function compare(a, b) {
function partition (line 29) | function partition(array, left, right, cmp) {
function quicksort (line 59) | function quicksort(array, left, right, cmp) {
FILE: src/sorting/quicksort.js
function compare (line 12) | function compare(a, b) {
function swap (line 25) | function swap(array, i, j) {
function partition (line 40) | function partition(array, left, right, compare) {
function quickSort (line 63) | function quickSort(array, left, right, cmp) {
FILE: src/sorting/recursive-insertionsort.js
function compare (line 4) | function compare(a, b) {
function recursiveInsertionSort (line 28) | function recursiveInsertionSort(array, cmp, max) {
FILE: src/sorting/selectionsort.js
function compare (line 4) | function compare(a, b) {
FILE: src/sorting/shellsort.js
function compare (line 4) | function compare(a, b) {
FILE: test/data-structures/linked-list.spec.js
function callback (line 137) | function callback(node){
FILE: test/data-structures/size-balanced-tree.spec.js
function checkNil (line 60) | function checkNil() {
function getRandomInt (line 89) | function getRandomInt(min, max) {
function getRandomIntInclusive (line 94) | function getRandomIntInclusive(min, max) {
FILE: test/graphs/others/topological-sort.spec.js
function runTs (line 32) | function runTs() {
FILE: test/others/minimax.spec.js
function getAllNextStates (line 13) | function getAllNextStates(state) {
function ticTacToe (line 144) | function ticTacToe() {
function simpleGame (line 241) | function simpleGame() {
FILE: test/sorting/sort.testcase.js
function createRandomArray (line 11) | function createRandomArray(config) {
function comparator (line 51) | function comparator(a, b) {
Condensed preview — 150 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (359K chars).
[
{
"path": ".eslintrc.json",
"chars": 1962,
"preview": "{\n \"env\": {\n \"browser\": true,\n \"jquery\": true,\n \"node\": true,\n \"es6\": true\n },\n \"globals\": {\n \"expect\""
},
{
"path": ".github/workflows/main.yml",
"chars": 286,
"preview": "name: Node.js CI\n\non: [push]\n\njobs:\n build:\n\n runs-on: ubuntu-latest\n\n steps:\n - uses: actions/checkout@v4\n "
},
{
"path": ".gitignore",
"chars": 52,
"preview": "node_modules\n.vscode\nnpm-debug.log\ndebug\ndist\n.idea\n"
},
{
"path": ".travis.yml",
"chars": 57,
"preview": "language: node_js\nnode_js:\n - \"8\"\nscript: npm run build\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3347,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2018 Minko Gechev\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "doc-config.json",
"chars": 904,
"preview": "{\n \"tags\": {\n \"allowUnknownTags\": true\n },\n \"source\": {\n \"include\": [\n \"./src/combinat"
},
{
"path": "gulpfile.js",
"chars": 452,
"preview": "const gulp = require('gulp');\nconst eslint = require('gulp-eslint');\nconst jasmine = require('gulp-jasmine');\n\ngulp.task"
},
{
"path": "package.json",
"chars": 1005,
"preview": "{\n \"name\": \"javascript-algorithms\",\n \"version\": \"0.0.0\",\n \"description\": \"Implementations of different computer scien"
},
{
"path": "readme.md",
"chars": 8565,
"preview": "## About\n\nThis repository contains JavaScript implementations of famous computer science algorithms.\n\nAPI reference with"
},
{
"path": "src/combinatorics/cartesianproduct.js",
"chars": 1293,
"preview": "(function (exports) {\n 'use strict';\n\n var cartesianProduct = (function () {\n var result;\n\n function cartesianPr"
},
{
"path": "src/combinatorics/combinations.js",
"chars": 1663,
"preview": "(function (exports) {\n 'use strict';\n\n var combinations = (function () {\n var res = [];\n\n function combinations("
},
{
"path": "src/combinatorics/permutations.js",
"chars": 1811,
"preview": "(function (exports) {\n 'use strict';\n var permutations = (function () {\n\n var res;\n\n function swap(arr, i, j) {\n"
},
{
"path": "src/combinatorics/variations-repetition.js",
"chars": 1623,
"preview": "(function (exports) {\n 'use strict';\n\n var variationsWithRepetition = (function () {\n var res;\n\n function variat"
},
{
"path": "src/compression/LZW/LZW.js",
"chars": 2191,
"preview": "/**\n * LZW Encoding/Decoding\n *\n * Lempel–Ziv–Welch (LZW) is a universal lossless data\n * compression algorithm. It is a"
},
{
"path": "src/compression/burrows-wheeler/burrows-wheeler.js",
"chars": 2793,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Burrows Wheeler.\n *\n * This algorithm is commonly used as a step i"
},
{
"path": "src/compression/runlength/runlength.js",
"chars": 1649,
"preview": "/**\n * Run-length encoding.\n * The idea of this algorithm is to remove the usless zeros and\n * give us representation of"
},
{
"path": "src/data-structures/avl-tree.js",
"chars": 21876,
"preview": "/**\n * AVL tree, a Binary Search Tree that satisfies the Height-Balance\n * Property.\n *\n * @example\n * var avlTree = req"
},
{
"path": "src/data-structures/binary-search-tree.js",
"chars": 12638,
"preview": "/**\n * Binary search tree.\n *\n * @example\n * var BST = require('path-to-algorithms/src/data-structures'+\n * '/binary-sea"
},
{
"path": "src/data-structures/bloomfilter.js",
"chars": 6612,
"preview": "/**\n * Bloomfilter and a bitmap.\n * Probablistic data structure useful for deduplication\n *\n * @example\n * // create a b"
},
{
"path": "src/data-structures/edge.js",
"chars": 478,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Graph edge.\n *\n * @constructor\n * @public\n * @param {Vertex} e"
},
{
"path": "src/data-structures/hash-table.js",
"chars": 6821,
"preview": "/**\n * Hash Table\n *\n * An associative array, that can map keys\n * (strings and numbers) to values in O(1).\n *\n * @examp"
},
{
"path": "src/data-structures/heap.js",
"chars": 4891,
"preview": "/**\n * A binary heap is a complete binary tree which\n * satisfies the heap ordering property.\n *\n * @example\n * var Heap"
},
{
"path": "src/data-structures/interval-tree.js",
"chars": 7784,
"preview": "/**\n * Interval tree is an ordered tree data structure to hold intervals.\n *\n * @example\n *\n * var IT = require('path-to"
},
{
"path": "src/data-structures/linked-list.js",
"chars": 5613,
"preview": "/**\n * Linked list.\n *\n * @example\n *\n * var LL = require('path-to-algorithms/src/data-structures/linked-list');\n *\n * v"
},
{
"path": "src/data-structures/red-black-tree.js",
"chars": 6991,
"preview": "/**\n * Red-Black tree is a data structure which is\n * a type of self-balancing binary search tree.\n *\n * @example\n *\n * "
},
{
"path": "src/data-structures/segment-tree.js",
"chars": 3216,
"preview": "/**\n * Implementation of a segment tree.\n *\n * @example\n * var SegmentTree = require('path-to-algorithms/src/data-struct"
},
{
"path": "src/data-structures/size-balanced-tree.js",
"chars": 8681,
"preview": "/**\n * Size balanced tree is a data structure which is\n * a type of self-balancing binary search tree that use\n * the tr"
},
{
"path": "src/data-structures/splay-tree.js",
"chars": 16624,
"preview": "/**\n * Splay Tree.\n *\n * @example\n * var STree = require('path-to-algorithms/src/data-structures'+\n * '/splay-tree');\n *"
},
{
"path": "src/data-structures/suffix-tree.js",
"chars": 1914,
"preview": "(function (exports) {\n 'use strict';\n\n function Node(val) {\n this.value = val;\n this.nodes = {};\n }\n\n function"
},
{
"path": "src/data-structures/vertex.js",
"chars": 304,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Graph vertex.\n *\n * @constructor\n * @public\n * @param {Number}"
},
{
"path": "src/graphics/bezier.js",
"chars": 556,
"preview": "(function (exports) {\n 'use strict';\n\n function linearBezier(p0, p1, t) {\n return p0 + t * (p1 - p0);\n }\n\n functi"
},
{
"path": "src/graphics/bresenham-line-drawing.js",
"chars": 1331,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Draws (prints) the given coordinates\n * @param {number} x The first"
},
{
"path": "src/graphics/graham.js",
"chars": 1760,
"preview": "(function(exports) {\n 'use strict';\n\n const slope = (p, a) => (a.y - p.y) / (a.x - p.x);\n\n const dist = (a, b) => Mat"
},
{
"path": "src/graphs/others/tarjan-connected-components.js",
"chars": 2114,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Tarjan's algorithm for finding the connected components in a graph.<br"
},
{
"path": "src/graphs/others/topological-sort.js",
"chars": 1738,
"preview": "(function (exports) {\n 'use strict';\n\n var topologicalSort = (function () {\n\n function topologicalSortHelper(node, "
},
{
"path": "src/graphs/searching/bfs.js",
"chars": 1954,
"preview": "(function (exports) {\n 'use strict';\n\n var bfs = (function () {\n\n function buildPath(parents, targetNode) {\n v"
},
{
"path": "src/graphs/searching/dfs.js",
"chars": 1582,
"preview": "(function (exports) {\n 'use strict';\n\n var dfs = (function () {\n\n function hasPath(graph, current, goal) {\n va"
},
{
"path": "src/graphs/shortest-path/bellman-ford.js",
"chars": 2707,
"preview": "/**\n * Bellman–Ford algorithm computes shortest paths from a single source\n * vertex to all of the other vertices in a w"
},
{
"path": "src/graphs/shortest-path/dijkstra.js",
"chars": 3903,
"preview": "(function (exports) {\n 'use strict';\n\n var dijkstra = (function () {\n\n var Heap = require('../../data-structures/he"
},
{
"path": "src/graphs/shortest-path/floyd-warshall.js",
"chars": 2574,
"preview": "(function (exports) {\n 'use strict';\n\n var floydWarshall = (function () {\n\n /**\n * Matrix used for the algorith"
},
{
"path": "src/graphs/spanning-trees/kruskal.js",
"chars": 2005,
"preview": "// Kruskal's algorithm for minimal spanning tree implemented with the UnionFind datastructure.\n\n(function(exports) {\n '"
},
{
"path": "src/graphs/spanning-trees/prim.js",
"chars": 4681,
"preview": "/**\n * Prim's algorithm is a greedy algorithm that finds a minimum\n * spanning tree for a connected weighted undirected "
},
{
"path": "src/others/fibonacci.js",
"chars": 778,
"preview": "/**\n * Nth number of fibonacci's sequence\n *\n * Returns the nth number of fibonacci's sequence.\n *\n * @public\n *\n * @exa"
},
{
"path": "src/others/fibonacciMemory.js",
"chars": 766,
"preview": "/**\r\n * Nth number of fibonacciMemory's sequence\r\n *\r\n * Returns the nth number of fibonacciMemory's sequence.\r\n *\r\n * @"
},
{
"path": "src/others/hanoi.js",
"chars": 1343,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Returns all movements needed to solve Hanoi Tower problem.\n *\n * @"
},
{
"path": "src/others/levenshtein-distance.js",
"chars": 1563,
"preview": "(function (exports) {\n 'use strict';\n\n var levenshteinDistance = (function () {\n\n function levenshteinDistance (s, "
},
{
"path": "src/others/min-coins-change.js",
"chars": 1434,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Returns the minimum number of coins from given set,\n * which sum equ"
},
{
"path": "src/others/minimax.js",
"chars": 3331,
"preview": "(function (exports) {\n 'use strict';\n /* eslint max-params: 0 */\n\n /**\n * @param {Function} getPossibleNextStatesFn "
},
{
"path": "src/others/minkowski-distance.js",
"chars": 2072,
"preview": "(function (exports) {\n 'use strict';\n\n var minkowskiDistance = (function () {\n\n function chebyshevDistance (x, y, l"
},
{
"path": "src/primes/is-prime.js",
"chars": 1103,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Advanced (optimised) method for checking if provided number is prime.\n"
},
{
"path": "src/primes/prime-factor-tree.js",
"chars": 1272,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Method will return list of all primes for provided number.\n * For ex"
},
{
"path": "src/primes/sieve-of-atkins.js",
"chars": 1939,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Sieve of Atkins.\n *\n * Modern algorithm for finding all prime numb"
},
{
"path": "src/primes/sieve-of-eratosthenes.js",
"chars": 1331,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Sieve of Eratosthenes.\n *\n * Simple, ancient algorithm for finding"
},
{
"path": "src/searching/binarysearch.js",
"chars": 1346,
"preview": "(function (exports) {\n 'use strict';\n\n function id (val) { return val; }\n function get (key) { return function (val) "
},
{
"path": "src/searching/interpolation-search.js",
"chars": 1676,
"preview": "(function(exports) {\n 'use strict';\n /**\n * Searches for specific element in a given array using\n * the interpolat"
},
{
"path": "src/searching/jump-search.js",
"chars": 1462,
"preview": "(function(exports) {\n 'use strict';\n /**\n * Searches for specific element in a given array using\n * the jump searc"
},
{
"path": "src/searching/knuth-morris-pratt.js",
"chars": 2018,
"preview": "(function (exports) {\n 'use strict';\n\n var kmp = (function () {\n function builtKMPTable(str) {\n var res = [];\n"
},
{
"path": "src/searching/linearSearch.js",
"chars": 637,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Searches for specific element in a given array\n * using the linear s"
},
{
"path": "src/searching/longest-common-subsequence.js",
"chars": 2682,
"preview": "(function (exports) {\n 'use strict';\n\n exports.longestCommonSubsequence = (function () {\n\n /**\n * Find the leng"
},
{
"path": "src/searching/longest-increasing-subsequence.js",
"chars": 3801,
"preview": "(function (exports) {\n 'use strict';\n\n exports.longestIncreasingSubsequence = (function () {\n\n /**\n * Find the i"
},
{
"path": "src/searching/maximum-subarray-divide-and-conquer.js",
"chars": 2532,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Accepts an array and range. Finds the maximum sum of elements\n * aro"
},
{
"path": "src/searching/maximum-subarray.js",
"chars": 1057,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Finds the maximum sum of the elements of a subarray in a given array\n "
},
{
"path": "src/searching/quickselect.js",
"chars": 1684,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Returns the n-th smallest element of list within\n * lo..hi inclusive"
},
{
"path": "src/searching/recursive-binarysearch.js",
"chars": 1731,
"preview": "(function (exports) {\n 'use strict';\n\n var binarySearch = (function () {\n /**\n * @private\n * @param {Array}"
},
{
"path": "src/sets/quickfind.js",
"chars": 1938,
"preview": "/**\n * Keeps track of a set of elements partitioned into a\n * number of disjoint (nonoverlapping) subsets.\n * Allows to "
},
{
"path": "src/sets/quickunion.js",
"chars": 2120,
"preview": "/**\n * Keeps track of a set of elements partitioned into a\n * number of disjoint (nonoverlapping) subsets.\n * Allows to "
},
{
"path": "src/sets/weightquickunion.js",
"chars": 2476,
"preview": "/**\n * Keeps track of a set of elements partitioned into a\n * number of disjoint (nonoverlapping) subsets.\n * Allows to "
},
{
"path": "src/shuffle/fisheryates.js",
"chars": 803,
"preview": "(function (exports) {\n\n 'use strict';\n\n /**\n * The shuffling algorithm of\n * Fisher-Yates.<br><br>\n * Time compl"
},
{
"path": "src/shuffle/richarddurstenfeld.js",
"chars": 966,
"preview": "(function (exports) {\n\n 'use strict';\n\n /**\n * Shuffle of an array elements.\n * This algorithm is modified version"
},
{
"path": "src/sorting/3-way-string-quicksort.js",
"chars": 1674,
"preview": "(function (exports) {\n 'use strict';\n\n var quicksort = (function () {\n\n function charAt(str, i) {\n return (i <"
},
{
"path": "src/sorting/bubblesort.js",
"chars": 1228,
"preview": "(function (exports) {\n 'use strict';\n\n function comparator(a, b) {\n return a - b;\n }\n\n /**\n * Bubble sort algor"
},
{
"path": "src/sorting/bucketsort.js",
"chars": 2985,
"preview": "(function (exports) {\n\n 'use strict';\n\n var bucketSort = (function () {\n\n /**\n * Insertionsort.\n *\n * @"
},
{
"path": "src/sorting/countingsort.js",
"chars": 2471,
"preview": "(function (exports) {\n 'use strict';\n\n var countingSort = (function () {\n\n /**\n * Gets the count of the element"
},
{
"path": "src/sorting/heapsort.js",
"chars": 2592,
"preview": "(function (exports) {\n 'use strict';\n\n function comparator(a, b) {\n return a - b;\n }\n\n var heapSort = (function ("
},
{
"path": "src/sorting/insertion-binary-sort.js",
"chars": 1708,
"preview": "(function (exports) {\n 'use strict';\n\n function comparator(a, b) {\n return a - b;\n }\n\n /**\n * Modified version "
},
{
"path": "src/sorting/insertionsort.js",
"chars": 1126,
"preview": "(function (exports) {\n 'use strict';\n\n function compare(a, b) {\n return a - b;\n }\n\n /**\n * Insertionsort algori"
},
{
"path": "src/sorting/lsd.js",
"chars": 1429,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Sorts strings lexicographically.<br><br>\n * Time complexity: O(N*M) "
},
{
"path": "src/sorting/mergesort.js",
"chars": 2918,
"preview": "(function (exports) {\n /**\n * Mergesort module.\n */\n 'use strict';\n\n var ll = require('../data-structures/linked-"
},
{
"path": "src/sorting/msd.js",
"chars": 1727,
"preview": "(function (exports) {\n 'use strict';\n\n function charCodeAt(str, i) {\n return (i < str.length) ? str.charCodeAt(i) :"
},
{
"path": "src/sorting/oddeven-sort.js",
"chars": 1066,
"preview": "(function (exports) {\n 'use strict';\n\n /**\n * Odd even sort algorithm.<br><br>\n * Complexity: O(N^2).\n *\n * @e"
},
{
"path": "src/sorting/quicksort-declarative.js",
"chars": 1652,
"preview": "(function (exports) {\n\n 'use strict';\n\n function compare(a, b) {\n return a - b;\n }\n\n /**\n * Quicksort algorithm"
},
{
"path": "src/sorting/quicksort-middle.js",
"chars": 2824,
"preview": "(function (exports) {\n\n 'use strict';\n\n function compare(a, b) {\n return a - b;\n }\n\n /**\n * Quicksort algorithm"
},
{
"path": "src/sorting/quicksort.js",
"chars": 2318,
"preview": "(function (exports) {\n\n 'use strict';\n\n /**\n * The quicksort algorithm. It's complexity is O(nlog n).\n *\n * @pub"
},
{
"path": "src/sorting/radixsort.js",
"chars": 2893,
"preview": "(function (exports) {\n 'use strict';\n\n var radixSort = (function () {\n\n /**\n * Returns the digit of a number th"
},
{
"path": "src/sorting/readme.md",
"chars": 1940,
"preview": "# Comparison of all sorting algorithms\n\n| Algorithm | Complexity "
},
{
"path": "src/sorting/recursive-insertionsort.js",
"chars": 1379,
"preview": "(function (exports) {\n 'use strict';\n\n function compare(a, b) {\n return a - b;\n }\n\n /**\n * Recursive version of"
},
{
"path": "src/sorting/selectionsort.js",
"chars": 1171,
"preview": "(function (exports) {\n 'use strict';\n\n function compare(a, b) {\n return a - b;\n }\n\n /**\n * Selection sort.<br><"
},
{
"path": "src/sorting/shellsort.js",
"chars": 1435,
"preview": "(function (exports) {\n 'use strict';\n\n function compare(a, b) {\n return a - b;\n }\n\n var shellSort = (function () "
},
{
"path": "test/compression/burrows-wheeler/burrows-wheeler.spec.js",
"chars": 452,
"preview": "var bw = require('../../../src/compression/burrows-wheeler/burrows-wheeler').burrowsWheeler;\n\ndescribe('Burrows Wheeler'"
},
{
"path": "test/data-structures/avl-tree.spec.js",
"chars": 6348,
"preview": "var mod = require('../../src/data-structures/avl-tree.js');\nvar Node = mod.Node;\nvar AVLTree = mod.AVLTree;\n\ndescribe('N"
},
{
"path": "test/data-structures/binary-search-tree.spec.js",
"chars": 2789,
"preview": "var mod = require('../../src/data-structures/binary-search-tree.js');\nvar Node = mod.Node;\nvar BinaryTree = mod.BinaryTr"
},
{
"path": "test/data-structures/bloomfilter.spec.js",
"chars": 1753,
"preview": "var mod = require('../../src/data-structures/bloomfilter.js');\nvar Bitmap = mod.Bitmap;\nvar Bloomfilter = mod.Bloomfilte"
},
{
"path": "test/data-structures/hash-table.spec.js",
"chars": 10268,
"preview": "var mod = require('../../src/data-structures/hash-table.js');\nvar Node = mod.Node;\nvar Hashtable = mod.Hashtable;\n\ndescr"
},
{
"path": "test/data-structures/heap.spec.js",
"chars": 2690,
"preview": "var mod = require('../../src/data-structures/heap.js');\nvar Heap = mod.Heap;\n\ndescribe('Heap', function () {\n 'use stri"
},
{
"path": "test/data-structures/interval-tree.spec.js",
"chars": 1397,
"preview": "var mod = require('../../src/data-structures/interval-tree.js');\nvar IntervalTree = mod.IntervalTree;\n\ndescribe('Interva"
},
{
"path": "test/data-structures/linked-list.spec.js",
"chars": 5682,
"preview": "var mod = require('../../src/data-structures/linked-list.js');\nvar Node = mod.Node;\nvar LinkedList = mod.LinkedList;\n\nde"
},
{
"path": "test/data-structures/red-black-tree.spec.js",
"chars": 3874,
"preview": "var mod = require('../../src/data-structures/red-black-tree.js');\nvar Vertex = mod.Node;\nvar RBTree = mod.RBTree;\nvar Co"
},
{
"path": "test/data-structures/segment-tree.spec.js",
"chars": 2947,
"preview": "var SegmentTree = require('../../src/data-structures/segment-tree.js')\n .SegmentTree;\n\nvar defaultAggregate = function "
},
{
"path": "test/data-structures/size-balanced-tree.spec.js",
"chars": 5409,
"preview": "var mod = require('../../src/data-structures/size-balanced-tree.js');\nvar Node = mod.Node;\nvar Nil = mod.Nil;\nvar SBTree"
},
{
"path": "test/data-structures/splay-tree.spec.js",
"chars": 2474,
"preview": "var mod = require('../../src/data-structures/splay-tree.js');\nvar Node = mod.Node;\nvar SplayTree = mod.SplayTree;\n\ndescr"
},
{
"path": "test/graphics/bezier.spec.js",
"chars": 1756,
"preview": "var bezier = require('../../src/graphics/bezier');\nvar linearBezier = bezier.linearBezier;\nvar quadraticBezier = bezier."
},
{
"path": "test/graphics/grapham.spec.js",
"chars": 568,
"preview": "var convexHull = require('../../src/graphics/graham').convexHull;\n\nconst points = [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n"
},
{
"path": "test/graphs/others/tarjan-connected-components.spec.js",
"chars": 826,
"preview": "var tj = require('../../../src/graphs/others/tarjan-connected-components').tarjanConnectedComponents;\n\nvar nonConnected "
},
{
"path": "test/graphs/others/topological-sort.spec.js",
"chars": 924,
"preview": "var ts = require('../../../src/graphs/others/topological-sort').topologicalSort;\n\ndescribe('Topological sort', function "
},
{
"path": "test/graphs/searching/bfs.spec.js",
"chars": 1377,
"preview": "/* jshint multistr: true */\n\nvar graph = [[0, 0, 0, 0, 1],\n [0, 0, 0, 1, 0],\n [0, 0, 0, 0, 0],\n "
},
{
"path": "test/graphs/searching/dfs.spec.js",
"chars": 1094,
"preview": "var dfs = require('../../../src/graphs/searching/dfs').dfs;\n\ndescribe('dfs', function () {\n 'use strict';\n\n it('should"
},
{
"path": "test/graphs/shortest-path/bellman-ford.spec.js",
"chars": 1076,
"preview": "var exported =\n require('../../../src/graphs/shortest-path/bellman-ford');\nvar bellmanFord = exported.bellmanFord;\nvar "
},
{
"path": "test/graphs/shortest-path/dijkstra.spec.js",
"chars": 764,
"preview": "var dijkstra =\n require('../../../src/graphs/shortest-path/dijkstra').dijkstra;\n\ndescribe('dijkstra', function () {\n '"
},
{
"path": "test/graphs/spanning-trees/kruskal.spec.js",
"chars": 1703,
"preview": "var kruskal = require('../../../src/graphs/spanning-trees/kruskal');\n\ndescribe('Kruskal', function() {\n 'use strict';\n\n"
},
{
"path": "test/others/fibonacci.spec.js",
"chars": 943,
"preview": "var mod = require('../../src/others/fibonacci.js');\nvar fibonacci = mod.fibonacci;\n\ndescribe('fibonacci algorithm', func"
},
{
"path": "test/others/fibonacciMemory.spec.js",
"chars": 903,
"preview": "var mod = require('../../src/others/fibonacciMemory.js');\nvar fibonacci = mod.fibonacciMemory;\n\ndescribe('fibonacci with"
},
{
"path": "test/others/levenshtein-distance.spec.js",
"chars": 1782,
"preview": "var mod = require('../../src/others/levenshtein-distance.js');\nvar levenshteinDistance = mod.levenshteinDistance;\n\ndescr"
},
{
"path": "test/others/min-coins-sum.spec.js",
"chars": 907,
"preview": "var minCoinsChange =\n require('../../src/others/min-coins-change.js').minCoinsChange;\n\ndescribe('Change making problem'"
},
{
"path": "test/others/minimax.spec.js",
"chars": 7350,
"preview": "const minimaxBuilder = require('../../src/others/minimax.js').minimaxBuilder;\n\ndescribe('Minimax', function () {\n 'use "
},
{
"path": "test/others/minkowski-distance.spec.js",
"chars": 1817,
"preview": "var mod = require('../../src/others/minkowski-distance.js');\nvar minkowskiDistance = mod.minkowskiDistance;\n\ndescribe('M"
},
{
"path": "test/primes/is-prime.spec.js",
"chars": 654,
"preview": "var isPrime = require('../../src/primes/is-prime').isPrime;\n\ndescribe('Advanced (optimised) method that checks number on"
},
{
"path": "test/primes/prime-factor-tree.spec.js",
"chars": 1025,
"preview": "var primeFactorTree = require('../../src/primes/prime-factor-tree').primeFactorTree;\n\ndescribe('Prime factor tree', func"
},
{
"path": "test/primes/sieve-of-atkins.spec.js",
"chars": 897,
"preview": "var sieveOfAtkins =\n require('../../src/primes/sieve-of-atkins').sieveOfAtkins;\n\ndescribe('Sieve Of Atkins', function ("
},
{
"path": "test/primes/sieve-of-eratosthenes.spec.js",
"chars": 951,
"preview": "var sieveOfEratosthenes =\n require('../../src/primes/sieve-of-eratosthenes').sieveOfEratosthenes;\n\ndescribe('Sieve Of E"
},
{
"path": "test/searching/binarysearch.spec.js",
"chars": 1147,
"preview": "var binarySearch =\n require('../../src/searching/binarysearch').binarySearch;\n\ndescribe('Binary search', function () {\n"
},
{
"path": "test/searching/interpolation-search.spec.js",
"chars": 679,
"preview": "var interpolationSearch = require('../../src/searching/interpolation-search')\n .interpolationSearch;\n\ndescribe('Interpo"
},
{
"path": "test/searching/jump-search.spec.js",
"chars": 564,
"preview": "var jumpSearch = require('../../src/searching/jump-search').jumpSearch;\n\ndescribe('Jump search', function() {\n 'use str"
},
{
"path": "test/searching/knuth-morris-pratt.spec.js",
"chars": 891,
"preview": "var indexOf = require('../../src/searching/knuth-morris-pratt').kmp;\n\ndescribe('The string searching algorithm of Knuth-"
},
{
"path": "test/searching/linearSearch.spec.js",
"chars": 832,
"preview": "var linearSearch =\n require('../../src/searching/linearSearch').linearSearch;\n\ndescribe('Linear Search', function () {\n"
},
{
"path": "test/searching/longest-common-subsequence.spec.js",
"chars": 1567,
"preview": "var longestCommonSubsequence =\n require('../../src/searching/' +\n 'longest-common-subsequence')\n .longestCommonSu"
},
{
"path": "test/searching/longest-increasing-subsequence.spec.js",
"chars": 1294,
"preview": "var longestIncreasingSubsequence =\n require('../../src/searching/' +\n 'longest-increasing-subsequence')\n .longest"
},
{
"path": "test/searching/maximum-subarray-divide-and-conquer.spec.js",
"chars": 1080,
"preview": "var maxSubArray =\n require('../../src/searching/maximum-subarray-divide-and-conquer')\n .maxSubarray;\n\ndescribe('Maximu"
},
{
"path": "test/searching/maximum-subarray.spec.js",
"chars": 978,
"preview": "var maxSubArray = require('../../src/searching/maximum-subarray').maxSubarray;\n\ndescribe('Maximum subarray', function() "
},
{
"path": "test/searching/quickselect.spec.js",
"chars": 895,
"preview": "var quickselect = require('../../src/searching/quickselect').quickselect;\n\ndescribe('quickselect', function () {\n 'use "
},
{
"path": "test/searching/recursive-binarysearch.spec.js",
"chars": 806,
"preview": "var binarySearch =\n require('../../src/searching/recursive-binarysearch').binarySearch;\n\ndescribe('Binary search', func"
},
{
"path": "test/sorting/3-way-string-quicksort.spec.js",
"chars": 994,
"preview": "var quicksort =\n require('../../src/sorting/3-way-string-quicksort.js').quicksort;\n\ndescribe('Most-Significant Digit', "
},
{
"path": "test/sorting/bubblesort.spec.js",
"chars": 170,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar bubbleSort =\n require('../../src/sorting/bubblesort.js').bubb"
},
{
"path": "test/sorting/bucketsort.spec.js",
"chars": 459,
"preview": "var bs =\n require('../../src/sorting/bucketsort').bucketSort;\n\ndescribe('bucketsort', function () {\n 'use strict';\n\n "
},
{
"path": "test/sorting/countingsort.spec.js",
"chars": 465,
"preview": "var cs =\n require('../../src/sorting/countingsort').countingSort;\n\ndescribe('countingsort', function () {\n 'use strict"
},
{
"path": "test/sorting/heapsort.spec.js",
"chars": 154,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar heapSort = require('../../src/sorting/heapsort.js').heapSort;\n\nsor"
},
{
"path": "test/sorting/insertionbinarysort.spec.js",
"chars": 229,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar insertionBinarySort =\n require('../../src/sorting/' +\n '"
},
{
"path": "test/sorting/insertionsort.spec.js",
"chars": 190,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar insertionSort = require('../../src/sorting/' +\n 'insertionsor"
},
{
"path": "test/sorting/lsd.spec.js",
"chars": 906,
"preview": "var lsd = require('../../src/sorting/lsd.js').lsd;\n\ndescribe('Least-Significant Digit', function () {\n 'use strict';\n\n "
},
{
"path": "test/sorting/mergesort.spec.js",
"chars": 165,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar mergeSort =\n require('../../src/sorting/mergesort.js').mergeS"
},
{
"path": "test/sorting/msd.spec.js",
"chars": 937,
"preview": "var msd = require('../../src/sorting/msd.js').msd;\n\ndescribe('Most-Significant Digit', function () {\n 'use strict';\n\n "
},
{
"path": "test/sorting/oddeven-sort.spec.js",
"chars": 468,
"preview": "var oes =\n require('../../src/sorting/oddeven-sort').oddEvenSort;\n\ndescribe('oddeven-sort', function () {\n 'use strict"
},
{
"path": "test/sorting/quicksort-declarative.spec.js",
"chars": 177,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar quickSort =\n require('../../src/sorting/quicksort-declarative"
},
{
"path": "test/sorting/quicksort-middle.spec.js",
"chars": 172,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar quickSort =\n require('../../src/sorting/quicksort-middle.js')"
},
{
"path": "test/sorting/quicksort.spec.js",
"chars": 165,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar quickSort =\n require('../../src/sorting/quicksort.js').quickS"
},
{
"path": "test/sorting/radixsort.spec.js",
"chars": 463,
"preview": "var rx =\n require('../../src/sorting/radixsort.js').radixSort;\n\ndescribe('radixsort', function () {\n 'use strict';"
},
{
"path": "test/sorting/recursiveinsertionsort.spec.js",
"chars": 237,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar recursiveInsertionSort = require('../../src/sorting/' +\n 'rec"
},
{
"path": "test/sorting/selectionsort.spec.js",
"chars": 192,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar selectionSort =\n require('../../src/sorting/selectionsort.js'"
},
{
"path": "test/sorting/shellsort.spec.js",
"chars": 166,
"preview": "var sortTestCase = require('./sort.testcase.js');\nvar shellSort = require('../../src/sorting/shellsort.js')\n .shell"
},
{
"path": "test/sorting/sort.testcase.js",
"chars": 1647,
"preview": "module.exports = function (sort, algorithmName, options) {\n 'use strict';\n\n options = options || {\n integers: false"
}
]
About this extraction
This page contains the full source code of the mgechev/javascript-algorithms GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 150 files (329.1 KB), approximately 98.7k tokens, and a symbol index with 119 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.