Home Reference Source

src/util/search/index.js

/* eslint import/prefer-default-export: "off" */

/**
 * Perform a binary search in a sorted array A to find the index i such that the search value is
 * larger than or equal to A[i], and strictly smaller than A[i+1]. Informally, this corresponds with
 * finding the interval in which the search value lies. Throws an error when the input value is
 * outside of the array range. Does not check whether the array is actually sorted.
 *
 * @param {Array.<number>} array - Sorted input array
 * @param {number} value - Value for which the interval should be found
 * @return {number} Index i of array element A[i] such that `value >= A[i] && value < A[i + 1]`
 */
export function binaryIntervalSearch(array, value) {
  // Check whether the element to search falls within the range of the array (i.e., the range from
  // the lowest array value (first index) and largest array value (last index))
  if (value < array[0] || value >= array[array.length - 1]) {
    throw new Error('Binary search target value is outside of the range of the array.');
  }

  // Let and right bounds to search in
  let l = 0;
  let r = array.length - 1;

  // Middle index between left and right bound
  let m;

  while (true) {
    // Recalculate middle index
    m = Math.floor((l + r) / 2);

    if (value < array[m]) {
      // Check whether we've found the right interval
      if (value >= array[m - 1]) {
        break;
      }

      // Change bounds to left half
      r = m - 1;
    } else {
      // Change bounds to right half
      l = m + 1;
    }
  }

  return m - 1;
}