UNPKG

ibowankenobi-mergesort

Version:

Merge Sort algorithm implementation without recursion, using cached binary trees

364 lines (331 loc) 11.7 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: mergesort.0.0.3.evergreen.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: mergesort.0.0.3.evergreen.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/** * Mergesort module * @module Mergesort */ (function (global, factory) { typeof exports === 'object' &amp;&amp; typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' &amp;&amp; define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Mergesort = factory()); }(this, (function () { 'use strict'; const temp = []; function sort(arr, l1, l2, f, o = 0){ let i = 0, j = 0, s1 = o, e1 = o + l1 - 1, s2 = e1 + 1, e2 = s2 + l2 - 1, state = "both not traversed"; if(f(arr[e1], arr[s2]) &lt;= 0){ return; } else if(f(arr[s1], arr[e2]) >= 0){ while(l2--){ temp[i++] = arr[s2++]; } while(l1--){ temp[i++] = arr[s1++]; } state = "skip"; } outer: while(state){ switch(state){ case "both not traversed": if(f(arr[s1], arr[s2]) > 0) { temp[i++] = arr[s2++]; } else { temp[i++] = arr[s1++]; } if (s1 > e1) { state = "left traversed"; continue outer; } else if (s2 > e2) { state = "right traversed"; continue outer; } continue outer; case "left traversed": temp[i++] = arr[s2++]; if (s2 > e2){ break outer; } continue outer; case "right traversed": temp[i++] = arr[s1++]; if (s1 > e1){ break outer; } continue outer; case "skip": break outer; } } while(i--){ arr[o++] = temp[j++]; } } function insertionSort(arr, l, f, o = 0){ let i = 0, j, u, temp; --l; while(i &lt; l){ j = i; u = o + j; temp = arr[u + 1]; while(~j &amp;&amp; f(arr[u], temp) > 0){ arr[u + 1] = arr[u]; --j,--u; } arr[u + 1] = temp; i++; } return arr; } function walk(arr, tree, f, hThreshold = 8, backtrack = false){ outer: while(tree){ let leaf = tree.firstChild; if(!leaf){ if(tree.p){ tree = tree.p; continue; } tree = null; continue; } while(leaf.firstChild){ leaf = leaf.firstChild; } if(leaf.nextSibling.firstChild){ tree = leaf.nextSibling; continue; } if(leaf.l &lt;= hThreshold){ insertionSort(arr, leaf.p.l, f, leaf.o); } else { sort(arr, leaf.l, leaf.nextSibling.l, f, leaf.o); } leaf = leaf.p; backtrack &amp;&amp; (leaf.lastChild = leaf.firstChild.nextSibling); leaf.firstChild = null; while(!leaf.nextSibling){ leaf = leaf.p || leaf; if(!leaf.p){ tree = leaf; continue outer; } } tree = leaf.nextSibling; } } function tree(l) { let node = { o: 0, l: l, p: null, nextSibling: null, prevSibling: null }, state = "down"; outer: while(state){ switch(state){ case "down": if(node.l &lt;= 1){ state = "right"; continue outer; } let nL = (node.l / 2) | 0; node.firstChild = { o: node.o, l: nL, p: node, nextSibling: null, prevSibling: null }; node.firstChild.nextSibling = node.lastChild = { o: node.o + nL, l: node.l - nL, p: node, nextSibling: null, prevSibling: node.firstChild }; node = node.firstChild; state = "down"; continue outer; case "right": if(!node.nextSibling){ state = "up"; continue outer; } node = node.nextSibling; state = "down"; continue outer; case "up": if(!node.p){ return node; } node = node.p; if(node.nextSibling){ state = "right"; continue outer; } state = "up"; continue outer; } } } function regen(tree){ outer: while(tree){ let leaf = tree.lastChild; if(!leaf){ if(tree.p){ tree = tree.p; continue; } tree = null; continue; } while(leaf.lastChild){ leaf = leaf.lastChild; } if(leaf.prevSibling.lastChild){ tree = leaf.prevSibling; continue; } leaf = leaf.p; leaf.firstChild = leaf.lastChild.prevSibling; leaf.lastChild = null; while(!leaf.prevSibling){ leaf = leaf.p || leaf; if(!leaf.p){ tree = leaf; continue outer; } } tree = leaf.prevSibling; } } /** * An optinal configuration object that can be passed to the `Mergesort` factory function * @typedef {Object} module:Mergesort~config * @property {number} threshold The threshold below where the algorithm temporarily switches over to insertion sort * @property {number} size Use this if you are going to consistently sort arrays of fixed size. * Refers to size of the array to be sorted, where a binary tree is precalculated. * The tree will be reused for each call of the returned `instance`. * For each use, the tree is *walked* by setting `firstChild` properties of leaf nodes to null * and then regenerated by setting them again from the `lastChild` property of their parent. * This option results in a performance gain for large (> 1M) arrays, where cost of creating * the tree is greater than the cost of walking + regenerating the tree. For small arrays, * it has the reverse effect. It is set to off by default. */ const undef = void(0); /** * Returns a `Mergesort` `instance` * * ```javascript * * let instance = Mergesort(); //switches to insertion sort for array fragments &lt; 16 * * instance = Mergesort({threshold: 64}); //will switch to insertion sort for fragments &lt; 64 * * instance = Mergesort({size:999}); //will throw an error if you try to sort arrays with length other than 999 * * ``` * * @alias module:Mergesort * * @param {module:Mergesort~config} config a configuration object with optional parameters (default 16) * @returns {module:Mergesort~instance} * */ function index( { threshold = 16, size = undef } = { threshold: 16, size: undef } ){ if(size &amp;&amp; typeof size !== "number"){ throw new Error("Size must be of type number"); } const hThreshold = threshold / 2, _tree = size ? tree(size) : undef, /** * * ```javascript * let instance = Mergesort(), * * inputArray = [{value:10},{value:1},{value:5}], * * compare = (a, b) => a.value - b.value; * * instance(inputArray, compare); //[{value:1}, ...] * * @namespace * @param {Array} ArrayToBeSorted - Input array to be sorted * @param {Function} Compare - compare function, same as in [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) * @returns {Array} input array */ instance = function(arr, f){ let _length = arr.length; if(_tree){ if (_length !== _tree.l) { throw new Error("Array length must be " + size); } temp.length = _length; walk(arr, _tree, f, hThreshold ,true); regen(_tree); } else { temp.length = _length; walk(arr, tree(_length), f, hThreshold); } temp.length = 0; return arr; }; return instance; } index.version = "0.0.3"; return index; }))); </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-Mergesort.html">Mergesort</a></li></ul><h3>Namespaces</h3><ul><li><a href="module-Mergesort-instance.html">instance</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a> on Tue Aug 10 2021 13:57:42 GMT+0200 (Central European Summer Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>