American Flag Sort

In-place MSD radix distribution using cycle-leader style bucket placement.

Best O(n) Avg O(n) Worst O(nk) Space O(k) Stable No In-place Yes Distribution

How it works

In-place MSD radix distribution using cycle-leader style bucket placement.

Implementation

function americanFlagSort(arr, stats) {
  const n = arr.length;
  if (n < 2) return;
  let max = arr[0];
  for (let i = 1; i < n; i++) {
    if (arr[i] > max) max = arr[i];
  }
  const RADIX = 16;
  let topExp = 1;
  while (Math.floor(max / topExp) >= RADIX) {
    topExp = topExp * RADIX;
  }
  const stackLo = new Array(n + 32).fill(0);
  const stackHi = new Array(n + 32).fill(0);
  const stackExp = new Array(n + 32).fill(0);
  const count = new Array(RADIX).fill(0);
  const start = new Array(RADIX).fill(0);
  const next = new Array(RADIX).fill(0);
  let top = 0;
  stackLo[top] = 0;
  stackHi[top] = n;
  stackExp[top] = topExp;
  top++;
  while (top > 0) {
    top--;
    const lo = stackLo[top];
    const hi = stackHi[top];
    const e = stackExp[top];
    if (hi - lo <= 1 || e === 0) continue;
    for (let d = 0; d < RADIX; d++) {
      count[d] = 0;
    }
    for (let i = lo; i < hi; i++) {
      const digit = Math.floor(arr[i] / e) % RADIX;
      count[digit]++;
    }
    let sum = lo;
    for (let d = 0; d < RADIX; d++) {
      start[d] = sum;
      next[d] = sum;
      sum = sum + count[d];
    }
    for (let b = 0; b < RADIX; b++) {
      const end = start[b] + count[b];
      while (next[b] < end) {
        const i = next[b];
        const digit = Math.floor(arr[i] / e) % RADIX;
        if (digit === b) {
          next[b]++;
        } else {
          const to = next[digit];
          const t = arr[i];
          arr[i] = arr[to];
          arr[to] = t;
          next[digit]++;
        }
      }
    }
    if (e > 1) {
      for (let b = 0; b < RADIX; b++) {
        if (count[b] > 1) {
          stackLo[top] = start[b];
          stackHi[top] = start[b] + count[b];
          stackExp[top] = Math.floor(e / RADIX);
          top++;
        }
      }
    }
  }
}