You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
4.1 KiB
217 lines
4.1 KiB
/**
|
|
* Mnemonist Binary Search Helpers
|
|
* ================================
|
|
*
|
|
* Typical binary search functions.
|
|
*/
|
|
|
|
/**
|
|
* Function returning the index of the search value in the array or `-1` if
|
|
* not found.
|
|
*
|
|
* @param {array} array - Haystack.
|
|
* @param {any} value - Needle.
|
|
* @return {number}
|
|
*/
|
|
exports.search = function(array, value, lo, hi) {
|
|
var mid = 0;
|
|
|
|
lo = typeof lo !== 'undefined' ? lo : 0;
|
|
hi = typeof hi !== 'undefined' ? hi : array.length;
|
|
|
|
hi--;
|
|
|
|
var current;
|
|
|
|
while (lo <= hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
current = array[mid];
|
|
|
|
if (current > value) {
|
|
hi = ~-mid;
|
|
}
|
|
else if (current < value) {
|
|
lo = -~mid;
|
|
}
|
|
else {
|
|
return mid;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
|
|
/**
|
|
* Same as above, but can use a custom comparator function.
|
|
*
|
|
* @param {function} comparator - Custom comparator function.
|
|
* @param {array} array - Haystack.
|
|
* @param {any} value - Needle.
|
|
* @return {number}
|
|
*/
|
|
exports.searchWithComparator = function(comparator, array, value) {
|
|
var mid = 0,
|
|
lo = 0,
|
|
hi = ~-array.length,
|
|
comparison;
|
|
|
|
while (lo <= hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
comparison = comparator(array[mid], value);
|
|
|
|
if (comparison > 0) {
|
|
hi = ~-mid;
|
|
}
|
|
else if (comparison < 0) {
|
|
lo = -~mid;
|
|
}
|
|
else {
|
|
return mid;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
|
|
/**
|
|
* Function returning the lower bound of the given value in the array.
|
|
*
|
|
* @param {array} array - Haystack.
|
|
* @param {any} value - Needle.
|
|
* @param {number} [lo] - Start index.
|
|
* @param {numner} [hi] - End index.
|
|
* @return {number}
|
|
*/
|
|
exports.lowerBound = function(array, value, lo, hi) {
|
|
var mid = 0;
|
|
|
|
lo = typeof lo !== 'undefined' ? lo : 0;
|
|
hi = typeof hi !== 'undefined' ? hi : array.length;
|
|
|
|
while (lo < hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
if (value <= array[mid]) {
|
|
hi = mid;
|
|
}
|
|
else {
|
|
lo = -~mid;
|
|
}
|
|
}
|
|
|
|
return lo;
|
|
};
|
|
|
|
/**
|
|
* Same as above, but can use a custom comparator function.
|
|
*
|
|
* @param {function} comparator - Custom comparator function.
|
|
* @param {array} array - Haystack.
|
|
* @param {any} value - Needle.
|
|
* @return {number}
|
|
*/
|
|
exports.lowerBoundWithComparator = function(comparator, array, value) {
|
|
var mid = 0,
|
|
lo = 0,
|
|
hi = array.length;
|
|
|
|
while (lo < hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
if (comparator(value, array[mid]) <= 0) {
|
|
hi = mid;
|
|
}
|
|
else {
|
|
lo = -~mid;
|
|
}
|
|
}
|
|
|
|
return lo;
|
|
};
|
|
|
|
/**
|
|
* Same as above, but can work on sorted indices.
|
|
*
|
|
* @param {array} array - Haystack.
|
|
* @param {array} array - Indices.
|
|
* @param {any} value - Needle.
|
|
* @return {number}
|
|
*/
|
|
exports.lowerBoundIndices = function(array, indices, value, lo, hi) {
|
|
var mid = 0;
|
|
|
|
lo = typeof lo !== 'undefined' ? lo : 0;
|
|
hi = typeof hi !== 'undefined' ? hi : array.length;
|
|
|
|
while (lo < hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
if (value <= array[indices[mid]]) {
|
|
hi = mid;
|
|
}
|
|
else {
|
|
lo = -~mid;
|
|
}
|
|
}
|
|
|
|
return lo;
|
|
};
|
|
|
|
/**
|
|
* Function returning the upper bound of the given value in the array.
|
|
*
|
|
* @param {array} array - Haystack.
|
|
* @param {any} value - Needle.
|
|
* @param {number} [lo] - Start index.
|
|
* @param {numner} [hi] - End index.
|
|
* @return {number}
|
|
*/
|
|
exports.upperBound = function(array, value, lo, hi) {
|
|
var mid = 0;
|
|
|
|
lo = typeof lo !== 'undefined' ? lo : 0;
|
|
hi = typeof hi !== 'undefined' ? hi : array.length;
|
|
|
|
while (lo < hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
if (value >= array[mid]) {
|
|
lo = -~mid;
|
|
}
|
|
else {
|
|
hi = mid;
|
|
}
|
|
}
|
|
|
|
return lo;
|
|
};
|
|
|
|
/**
|
|
* Same as above, but can use a custom comparator function.
|
|
*
|
|
* @param {function} comparator - Custom comparator function.
|
|
* @param {array} array - Haystack.
|
|
* @param {any} value - Needle.
|
|
* @return {number}
|
|
*/
|
|
exports.upperBoundWithComparator = function(comparator, array, value) {
|
|
var mid = 0,
|
|
lo = 0,
|
|
hi = array.length;
|
|
|
|
while (lo < hi) {
|
|
mid = (lo + hi) >>> 1;
|
|
|
|
if (comparator(value, array[mid]) >= 0) {
|
|
lo = -~mid;
|
|
}
|
|
else {
|
|
hi = mid;
|
|
}
|
|
}
|
|
|
|
return lo;
|
|
};
|