Merge Sort Lesson- Complete Computer Science Tutorial
What Merge Sort Actually Is
Merge Sort is a divide-and-conquer sorting algorithm. It splits an array in half repeatedly until you get single elements, then merges those elements back together in sorted order.
That's the whole thing. Split, sort, merge. No magic.
It was invented by John von Neumann in 1945. It's been around longer than most of the computers you're using right now.
Why You Should Care
Merge Sort guarantees O(n log n) time complexity in all cases. Worst, average, best—same performance.
Compare that to Quick Sort, which can degrade to O(n²) if you pick bad pivots. Merge Sort doesn't have that problem.
It's also stable. If two elements have equal values, their original order is preserved. This matters when you're sorting objects by multiple criteria.
How Merge Sort Works
The Divide Step
You take an array and split it in half. Then you split each half in half. Keep going until every element is isolated in its own array.
Example with [38, 27, 43, 3, 9, 82, 10]:
- Split into [38, 27, 43, 3] and [9, 82, 10]
- Split into [38, 27], [43, 3], [9, 82], [10]
- Split into [38], [27], [43], [3], [9], [82], [10]
The Conquer (Merge) Step
Now you merge adjacent arrays, comparing elements and building sorted results.
- Merge [38] and [27] → [27, 38]
- Merge [43] and [3] → [3, 43]
- Merge [9] and [82] → [9, 82]
- Merge [10] with itself → [10]
Continue merging:
- Merge [27, 38] and [3, 43] → [3, 27, 38, 43]
- Merge [9, 82] and [10] → [9, 10, 82]
Final merge:
- Merge [3, 27, 38, 43] and [9, 10, 82] → [3, 9, 10, 27, 38, 43, 82]
Sorted.
Time and Space Complexity
| Case | Time Complexity | Space Complexity |
|---|---|---|
| Best | O(n log n) | O(n) |
| Average | O(n log n) | O(n) |
| Worst | O(n log n) | O(n) |
The space complexity is the tradeoff. Merge Sort needs O(n) extra space for the temporary arrays during merging. Quick Sort can run in-place with O(log n) space.
When to Use Merge Sort
Use it when:
- You need stable sorting
- Worst-case performance matters more than average case
- You're sorting linked lists (can be done with O(1) space)
- You're dealing with external sorting (data too large for RAM)
- You're working with parallel processing (halves can be sorted independently)
Skip it when:
- Memory is severely constrained
- You're sorting primitive types in languages like C/C++ (cache performance suffers)
Merge Sort vs Other Algorithms
| Algorithm | Best Time | Avg Time | Worst Time | Space | Stable |
|---|---|---|---|---|---|
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes |
Implementation in Python
Here's a working implementation. No frills, no class wrappers—just the algorithm.
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
Usage:
numbers = [64, 34, 25, 12, 22, 11, 90]
sorted_numbers = merge_sort(numbers)
print(sorted_numbers) # [11, 12, 22, 25, 34, 64, 90]
Implementation in JavaScript
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(left.slice(i)).concat(right.slice(j));
}
Common Mistakes
- Forgetting the base case. Without `if len(arr) <= 1`, you'll get infinite recursion.
- Not handling remaining elements. After the main while loop, one array will have leftover items. You need to append them.
- Creating too many temporary arrays. In production, you might want to allocate one result array and reuse it to reduce allocations.
- Using it for small arrays. For arrays under ~10 elements, Insertion Sort is faster due to lower overhead.
The Bottom Line
Merge Sort is reliable. It performs consistently, it's stable, and it's easy to understand. The trade-off is memory usage.
For most general-purpose sorting, languages use hybrid approaches—Introsort (Quick Sort + Heap Sort + Insertion Sort) or Timsort (Merge Sort + Insertion Sort). Python's `sorted()` uses Timsort. Java's `Arrays.sort()` uses Dual-Pivot Quick Sort for primitives and Timsort for objects.
But when you need guaranteed O(n log n) performance or stable sorting, Merge Sort is the straightforward choice. No gimmicks.