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.
Divide: split the array into two halves. Conquer: sort each half (recursively, with merge sort). Combine: merge the two sorted halves.
The code
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));1 3 9 10 27 38 43 82
Why O(n log n)?
| Property | Merge sort |
|---|---|
O(n log n) | |
O(n) for the buffer (+ O(log n) stack) | |
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 BYqueries.
{ 1, 3, 5, 7 } and { 2, 3, 6, 7, 9 } → 1 2 3 5 6 7 9.
Show a hint
Show the solution
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])));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.