3-Way Merge Sort

Splits into three parts instead of two. Slightly fewer comparisons than standard merge sort in theory.

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

How it works

Splits into three parts instead of two. Slightly fewer comparisons than standard merge sort in theory.

Implementation

function merge3Sort(arr, stats) {
  const n = arr.length;
  function merge3Way(lo, mid1, mid2, hi) {
    const merged = [];
    let i = lo, j = mid1, k = mid2;
    while (i < mid1 && j < mid2 && k < hi) {
      compare(i, j);
      let pick;
      if (arr[i] <= arr[j]) {
        compare(i, k);
        if (arr[i] <= arr[k]) pick = i; else pick = k;
      } else {
        compare(j, k);
        if (arr[j] <= arr[k]) pick = j; else pick = k;
      }
      if (pick === i) merged.push(arr[i++]); else if (pick === j) merged.push(arr[j++]); else merged.push(arr[k++]);
    }
    while (i < mid1 && j < mid2) {
      compare(i, j);
      if (arr[i] <= arr[j]) merged.push(arr[i++]); else merged.push(arr[j++]);
    }
    while (i < mid1 && k < hi) {
      compare(i, k);
      if (arr[i] <= arr[k]) merged.push(arr[i++]); else merged.push(arr[k++]);
    }
    while (j < mid2 && k < hi) {
      compare(j, k);
      if (arr[j] <= arr[k]) merged.push(arr[j++]); else merged.push(arr[k++]);
    }
    while (i < mid1) merged.push(arr[i++]);
    while (j < mid2) merged.push(arr[j++]);
    while (k < hi) merged.push(arr[k++]);
    for (let p = 0; p < merged.length; p++) {
      arr[lo + p] = merged[p];
      write(lo + p, merged[p]);
    }
  }
  function sort3(lo, hi) {
    if (hi - lo < 2) return;
    const third = Math.max(1, Math.floor((hi - lo) / 3));
    const mid1 = lo + third;
    const mid2 = lo + 2 * third;
    sort3(lo, mid1);
    sort3(mid1, mid2);
    sort3(mid2, hi);
    merge3Way(lo, mid1, mid2, hi);
    checkpoint(lo, n);
  }
  sort3(0, n);
}