<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. DSA
  3. Searching and sorting
All lessons in this course

Lesson 15 of 50 15 minIntermediate

Merge sort

Divide the array in half, sort each half, merge the sorted halves: a guaranteed O(n log n), stable sort, and the merge step you will reuse in many problems.

Merge sort is the classic divide and conquer algorithm. It rests on one easy fact: merging two lists that are already sorted into one sorted list is fast. You only ever need to compare the two front items.

  1. Divide: split the array into two halves.
  2. Conquer: sort each half (recursively, with merge sort).
  3. Combine: merge the two sorted halves.

The recursion stops at pieces of one item, which are sorted by definition. Try the merge step first, then watch the whole sort:

Interactive

The merge step, then the whole sort

Part 1: merging two sorted lists only ever compares the two front items.

Left391527
Right48203041
Result
Both halves are already sorted. Compare the two front items and take the smaller one.

Part 2: merge sort splits until every piece has one item (a single item is always sorted), then merges pairs back up.

split
38 27 43 3 9 82 10 1
Start: 8 unsorted items.

The code

MergeSort.cs
static void MergeSort(int[] a){    var buffer = new int[a.Length];          // one shared buffer: O(n) extra memory    Sort(a, buffer, 0, a.Length - 1);} static void Sort(int[] a, int[] buffer, int lo, int hi){    if (lo >= hi) return;                    // 0 or 1 item: already sorted    int mid = lo + (hi - lo) / 2;    Sort(a, buffer, lo, mid);                // sort the left half    Sort(a, buffer, mid + 1, hi);            // sort the right half    Merge(a, buffer, lo, mid, hi);           // combine} static void Merge(int[] a, int[] buffer, int lo, int mid, int hi){    int i = lo, j = mid + 1, k = lo;    while (i <= mid && j <= hi)        buffer[k++] = a[i] <= a[j] ? a[i++] : a[j++];   // <= keeps it stable    while (i <= mid) buffer[k++] = a[i++];              // leftovers    while (j <= hi)  buffer[k++] = a[j++];    Array.Copy(buffer, lo, a, lo, hi - lo + 1);         // copy back} int[] data = { 38, 27, 43, 3, 9, 82, 10, 1 };MergeSort(data);Console.WriteLine(string.Join(" ", data));
Output
1 3 9 10 27 38 43 82

Why O(n log n)?

Draw the recursion as a tree. Each level splits every piece in half, so there are log₂ n levels. At every level, the merges together touch each of the n items once: O(n) work per level. Total: O(n) × log n = O(n log n). This holds for every input, sorted, reversed or random: merge sort has no bad case.

PropertyMerge sort
Time (best, average, worst)O(n log n)
Extra memoryO(n) for the buffer (+ O(log n) stack)
StableYes
In placeNo (for arrays)

Where merge sort shines

  • Guaranteed performance: no input can make it slow, which matters for real-time or safety-related code.
  • Stability: sorting by several keys one after another works.
  • Linked lists: merging relinks nodes, so it needs no extra buffer and no random access. It is the standard way to sort a linked list.
  • Huge data (external sorting): sort chunks that fit in memory, write them to disk, then merge the sorted files. Databases do exactly this for big ORDER BY queries.
Quick check

How many levels of splitting does merge sort need for 1,024 items?

Quick check

What is the main disadvantage of merge sort on arrays?

Practice

Two sorted arrays of beam IDs may share some IDs. Merge them into one sorted list without duplicates in a single O(a + b) pass. { 1, 3, 5, 7 } and { 2, 3, 6, 7, 9 } → 1 2 3 5 6 7 9.

Show a hint

Use the merge loop. When the two front values are equal, take one and advance both indexes. Only add a value if it differs from the last one added.

Show the solution
Solution.cs
static List<int> Union(int[] a, int[] b){    var result = new List<int>();    int i = 0, j = 0;    while (i < a.Length || j < b.Length)    {        int v;        if (j >= b.Length || (i < a.Length && a[i] < b[j])) v = a[i++];        else if (i >= a.Length || b[j] < a[i]) v = b[j++];        else { v = a[i]; i++; j++; }            // equal: take once         if (result.Count == 0 || result[^1] != v)            result.Add(v);    }    return result;} Console.WriteLine(string.Join(" ", Union([1, 3, 5, 7], [2, 3, 6, 7, 9])));
Output
1 2 3 5 6 7 9

Remember

  • Merge sort splits in half, sorts each half recursively, and merges the sorted halves.
  • Merging two sorted lists is O(n): compare only the front items.
  • log n levels × O(n) per level = O(n log n) for every input.
  • It is stable but needs O(n) extra memory on arrays; it is ideal for linked lists and huge files.
0 of 50 lessons completed