function medianOfMedians(A, left, right, i) {
while(true) {
if(left === right) {
return A[left];
}
let pivotIndex = pivot(A, left, right);
pivotIndex = partition(A, left, right, pivotIndex);
if(i === pivotIndex) {
return A[pivotIndex];
}
else if(i < pivotIndex) {
right = pivotIndex - 1;
}
else {
left = pivotIndex + 1;
}
}
}
function pivot(A, left, right) {
if(right - left < 5) {
return insertion_sort(A, left, right);
}
for(let i = left; i <= right; i += 5) {
let subRight = i + 4;
if(subRight > right) {
subRight = right;
}
let median5 = insertion_sort(A, i, subRight);
swap(A[median5], A[left + Math.floor((i - left) / 5)]);
}
return medianOfMedians(A,
left,
left + Math.floor((right - left) / 5),
left + Math.floor((right - left) / 10));
}
function partition(A, left, right, pivotIndex) {
let pivotValue = A[pivotIndex];
swap(A[pivotIndex], A[right]);
let storeIndex = left;
for(let i = left; i < right; ++i) {
if(A[i] < pivotValue) {
swap(A[storeIndex], A[i]);
storeIndex++;
}
}
swap(A[storeIndex], A[right]);
return storeIndex;
}
function insertion_sort(A, left, right) {
let i, j, tmp;
for(i = left + 1; i <= right; ++i){
let tmp = A[i];
for(j = i; j > left && A[j - 1] > tmp; j--) {
A[j] = A[j - 1];
}
A[j] = tmp;
}
return left + Math.floor((right - left) / 2);
}