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.
Code
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];
}Report a problem with this exampleOpens a pre-filled issue on GitHub.