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
			| 
											3 years ago
										 | /** | ||
|  |  * 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; | ||
|  | }; |