Skip to main content
← All posts

Bottom-Up Merge Sort: Mechanism, Complexity Analysis & Interactive Visualizer

Md. Harun-Or-RoshidNov 5, 20269 min readArticle
Bottom-Up Merge Sort: Mechanism, Complexity Analysis & Interactive Visualizer
Divide & Conquer · Article 8 of 62

Bottom-Up Merge Sort

Same merges, no recursion. Walk over the array in runs of size 1, then 2, then 4, doubling each pass until the whole array is one run.

How it works

The recursive Merge Sort splits then merges. Bottom-Up Merge Sort flips this around: it starts assuming runs of length 1 are already sorted, then merges adjacent runs into runs of length 2, then 4, and so on.

  1. Start with run width w = 1.
  2. Walk the array: merge each pair of adjacent runs of width w into one run of width 2w.
  3. Double w and repeat until w ≥ n.

The total work and stability are identical to top-down Merge Sort. What changes: no recursion, no function-call stack, and slightly better cache behavior because passes are sequential. This formulation is preferred for external/disk-based merge sort.

Complexity

Best time
O(n log n)
Average time
O(n log n)
Worst time
O(n log n)
Extra space
O(n)
Stable
Yes
In-place
No
Bottom-up form is the natural model for external sorting: each pass is a sequential read + write over the data, which is exactly how spinning disks and SSDs want to be used.

Interactive visualization

Pseudocode

procedure bottomUpMergeSort(A):
  n ← length(A)
  w ← 1
  while w < n:
    for lo from 0 to n − 1 step 2w:
      mid ← min(lo + w − 1, n − 1)
      hi  ← min(lo + 2w − 1, n − 1)
      merge(A, lo, mid, hi)
    w ← 2w

JavaScript implementation

function bottomUpMergeSort(arr) {
  const n = arr.length;
  for (let w = 1; w < n; w *= 2) {
    for (let lo = 0; lo < n; lo += 2 * w) {
      const m  = Math.min(lo + w - 1, n - 1);
      const hi = Math.min(lo + 2 * w - 1, n - 1);
      merge(arr, lo, m, hi);
    }
  }
  return arr;
}

function merge(arr, lo, m, hi) {
  const aux = arr.slice(lo, hi + 1);
  let i = 0, j = m - lo + 1, k = lo;
  while (i <= m - lo && j <= hi - lo) {
    if (aux[i] <= aux[j]) {
      arr[k] = aux[i]; i++;
    } else {
      arr[k] = aux[j]; j++;
    }
    k++;
  }
  while (i <= m - lo) { arr[k] = aux[i]; i++; k++; }
  while (j <= hi - lo) { arr[k] = aux[j]; j++; k++; }
}

Pros and cons

Pros

  • No recursion — uses constant stack space.
  • Identical asymptotic behavior to top-down Merge Sort.
  • Excellent sequential I/O pattern — ideal for external sorting.
  • Easy to parallelize per pass.

Cons

  • Still needs O(n) auxiliary buffer.
  • Slightly worse cache behavior than top-down on in-memory arrays.
  • Not in-place.

When to use it

  • External merge sort on disk-resident data.
  • Stack-limited environments (embedded, scripted languages with low recursion depth).
  • Pipeline-friendly data processing systems.
Up next: In-Place Merge Sort — a wildly different idea: pick a pivot, partition the array into < and ≥, recurse on each side.
Share:
Share on X
Share on LinkedIn
Share on Facebook
Share on Reddit
Share on WhatsApp
Share on Telegram
Copy link

Related reading

Bottom-Up Merge Sort Visual Guide | Draftsbook · Draftsbook