Grail Sort

Block-based stable sorting family balancing merge performance with tiny extra memory.

Best O(n) Avg O(n log n) Worst O(n log n) Space O(1) Stable Yes In-place Yes Comparison-based

How it works

Block-based stable sorting family balancing merge performance with tiny extra memory.

Implementation

function grailSort(arr, stats) {
  const n = arr.length;
  const block = Math.max(4, Math.floor(Math.sqrt(n || 1)));
  function insertion(lo, hi) {
    for (let i = lo + 1; i <= hi; i++) {
      const key = arr[i];
      let j = i - 1;
      while (j >= lo) {
        compare(j, i);
        if (arr[j] <= key) break;
        arr[j + 1] = arr[j];
        write(j + 1, arr[j + 1]);
        j--;
      }
      arr[j + 1] = key;
      write(j + 1, key);
    }
  }
  function merge(lo, mid, hi) {
    const left = arr.slice(lo, mid + 1);
    let i = 0;
    let j = mid + 1;
    let k = lo;
    while (i < left.length && j <= hi) {
      compare(lo + i, j);
      if (left[i] <= arr[j]) arr[k++] = left[i++]; else arr[k++] = arr[j++];
      write(k - 1, arr[k - 1]);
    }
    while (i < left.length) {
      arr[k++] = left[i++];
      write(k - 1, arr[k - 1]);
    }
  }
  for (let i = 0; i < n; i += block) {
    insertion(i, Math.min(i + block - 1, n - 1));
  }
  for (let width = block; width < n; width <<= 1) {
    for (let i = 0; i < n; i += width << 1) {
      const lo = i;
      const mid = Math.min(i + width - 1, n - 1);
      const hi = Math.min(i + (width << 1) - 1, n - 1);
      if (mid < hi) merge(lo, mid, hi);
    }
  }
}