// JavaScript implementation of the Worst Case Linear Time algorithm
// to find the k-th smallest element using Median of Medians
// Returns median of a small group (size <= 5)
function getMedian(group) {
group.sort((a, b) => a - b);
return group[Math.floor(group.length / 2)];
}
// Function to Partition array from index
// l to r around the pivot value x
function partitionAroundPivot(arr, l, r, x) {
// Move pivot x to end
let i;
for (i = l; i < r; i++) {
if (arr[i] === x) break;
}
[arr[i], arr[r]] = [arr[r], arr[i]];
// Standard partition logic
i = l;
for (let j = l; j < r; j++) {
if (arr[j] <= x) {
[arr[i], arr[j]] = [arr[j], arr[i]];
i++;
}
}
[arr[i], arr[r]] = [arr[r], arr[i]];
// Final position of pivot
return i;
}
// Recursively finds the k-th smallest element in arr[l..r]
function selectKthSmallest(arr, l, r, k) {
if (k > 0 && k <= r - l + 1) {
let n = r - l + 1;
let medians = [];
// Divide array into groups of 5 and store their medians
let i;
for (i = 0; i < Math.floor(n / 5); i++) {
let group = arr.slice(l + i * 5, l + i * 5 + 5);
medians.push(getMedian(group));
}
// Handle the last group with less than 5 elements
if (i * 5 < n) {
let lastGroup = arr.slice(l + i * 5, l + i * 5 + (n % 5));
medians.push(getMedian(lastGroup));
}
// Find median of medians
let pivot;
if (medians.length === 1) {
pivot = medians[0];
} else {
pivot = selectKthSmallest(medians, 0, medians.length - 1,
Math.floor(medians.length / 2));
}
// Partition array and get position of pivot
let pos = partitionAroundPivot(arr, l, r, pivot);
// If position matches k, return result
if (pos - l === k - 1) return arr[pos];
// Recur on left or right part accordingly
if (pos - l > k - 1)
return selectKthSmallest(arr, l, pos - 1, k);
return selectKthSmallest(arr, pos + 1, r, k - pos + l - 1);
}
return Infinity;
}
// Function to find kth Smallest in Array
function kthSmallest(arr, k) {
return selectKthSmallest(arr, 0, arr.length - 1, k);
}
// Driver code
let arr = [7, 10, 4, 3, 20, 15];
let k = 3;
console.log(kthSmallest(arr, k));