Loser Tree Sort

Tournament-tree k-way merge method optimized for repeatedly selecting next minimum.

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

How it works

Tournament-tree k-way merge method optimized for repeatedly selecting next minimum.

Implementation

function loserTreeSort(arr, stats) {
  const n = arr.length;
  if (n < 2) return;
  const source = [...arr];
  const runSize = Math.min(n, Math.max(8, Math.floor(Math.sqrt(n))));
  const runs = [];
  const sortRun = run => {
    for (let i = 1; i < run.length; i++) {
      const value = run[i];
      let j = i - 1;
      while (j >= 0) {
        if (run[j] <= value) break;
        run[j + 1] = run[j];
        j--;
      }
      run[j + 1] = value;
    }
    return run;
  };
  for (let i = 0; i < n; i += runSize) {
    const run = source.slice(i, Math.min(i + runSize, n));
    runs.push(sortRun(run));
  }
  const k = runs.length;
  const idx = new Array(k).fill(0);
  let previewWrite = 0;
  for (let runIndex = 0; runIndex < runs.length; runIndex++) {
    const run = runs[runIndex];
    for (let valueIndex = 0; valueIndex < run.length; valueIndex++) {
      const value = run[valueIndex];
      arr[previewWrite] = value;
      write(previewWrite, value);
      previewWrite++;
    }
  }
  const value = i => {
    if (i < 0 || i >= k || idx[i] >= runs[i].length) return Infinity;
    return runs[i][idx[i]];
  };
  let leafCount = 1;
  while (leafCount < k) leafCount <<= 1;
  const selectWinner = (node, loserTree) => {
    if (node >= leafCount) {
      const player = node - leafCount;
      return player < k ? player : -1;
    }
    const leftWinner = selectWinner(node * 2, loserTree);
    const rightWinner = selectWinner(node * 2 + 1, loserTree);
    const leftValue = value(leftWinner);
    const rightValue = value(rightWinner);
    if (leftWinner >= 0 && rightWinner >= 0) {}
    if (leftValue <= rightValue) {
      loserTree[node] = rightWinner;
      return leftWinner;
    }
    loserTree[node] = leftWinner;
    return rightWinner;
  };
  for (let out = 0; out < n; out++) {
    const loserTree = new Array(leafCount * 2).fill(-1);
    const winner = selectWinner(1, loserTree);
    arr[out] = value(winner);
    write(out, arr[out]);
    markSorted(out);
    idx[winner]++;
  }
}