ibowankenobi-mergesort
Version:
Merge Sort algorithm implementation without recursion, using cached binary trees
92 lines (86 loc) • 3.34 kB
JavaScript
import temp from './temp.js';
import walk from './walk.js';
import tree from './tree.js';
import regen from './regen.js';
/**
* 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 < 16
*
* instance = Mergesort({threshold: 64}); //will switch to insertion sort for fragments < 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}
*
*/
export default function(
{
threshold = 16,
size = undef
}
= {
threshold: 16,
size: undef
}
){
if(size && 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;
}