Quickselect For Kth Smallest Element

Find the k-th smallest value in average linear time with randomized quickselect, zero-based ranks and a non-mutating input copy.

JavascriptData Integrity

Code

snippet
function swap(values, left, right) {
  const temporary = values[left];
  values[left] = values[right];
  values[right] = temporary;
}

export function quickselect(values, k, options = {}) {
  if (!Array.isArray(values)) throw new TypeError("values must be an array");
  if (!Number.isInteger(k) || k < 0 || k >= values.length) {
    throw new RangeError("k must be an integer within the array bounds");
  }
  const random = options.random ?? Math.random;
  if (typeof random !== "function") throw new TypeError("random must be a function");

  const data = values.slice();
  let left = 0;
  let right = data.length - 1;

  while (left < right) {
    const sample = random();
    if (!(sample >= 0 && sample < 1)) {
      throw new RangeError("random must return a value in [0, 1)");
    }
    const pivotIndex = left + Math.floor(sample * (right - left + 1));
    swap(data, pivotIndex, right);
    const pivot = data[right];
    let store = left;
    for (let index = left; index < right; index += 1) {
      if (data[index] < pivot) {
        swap(data, store, index);
        store += 1;
      }
    }
    swap(data, store, right);
    if (store === k) return data[store];
    if (store < k) left = store + 1;
    else right = store - 1;
  }
  return data[left];
}