Merge Sort in Java
Problem
Merge sort is a divide-and-conquer algorithm: it keeps halving the array until each piece holds one element, then merges neighbouring pieces back together in sorted order.
Given an array of integers, sort it in ascending order using merge sort.
Java Program
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] arr = {29, 4, 17, 8, 35, 12, 1};
mergeSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
static void mergeSort(int[] arr, int left, int right) {
if (left >= right) return; // zero or one element is already sorted
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
static void merge(int[] arr, int left, int mid, int right) {
int[] leftPart = Arrays.copyOfRange(arr, left, mid + 1);
int[] rightPart = Arrays.copyOfRange(arr, mid + 1, right + 1);
int i = 0, j = 0, k = left;
while (i < leftPart.length && j < rightPart.length) {
// <= keeps equal values in their original order, which makes the sort stable
arr[k++] = leftPart[i] <= rightPart[j] ? leftPart[i++] : rightPart[j++];
}
while (i < leftPart.length) arr[k++] = leftPart[i++]; // copy whatever is left over
while (j < rightPart.length) arr[k++] = rightPart[j++];
}
}Output
Core Logic
Sorting is easy for tiny pieces and merging two sorted lists is cheap, so the array is split until every piece is trivially sorted, then stitched back together pair by pair.
- 1
mergeSort(arr, left, right)returns immediately whenleft >= right, since a range of zero or one element is already sorted. - 2Otherwise it finds
mid, sortsleft..midandmid+1..rightrecursively, then callsmerge. - 3
mergecopies both halves into temporary arrays and repeatedly writes the smaller front value back intoarr. - 4When one half runs out, the remaining values of the other half are copied over unchanged.
[4, 29] and [8, 17] merge by comparing their fronts: 4 is taken first, then 8 and 17 (both smaller than 29), and finally 29, giving [4, 8, 17, 29].Key Point: Using <= in the merge comparison takes the left value first when two are equal, which keeps equal elements in their original order — that's what makes merge sort a stable sort.
Why: The array is halved about log n times and every level of merging touches all n elements, while each merge needs temporary copies of the halves.
Key Concepts
Approach 2: Bottom-Up (Iterative)
import java.util.Arrays;
public class MergeSortBottomUp {
public static void main(String[] args) {
int[] arr = {29, 4, 17, 8, 35, 12, 1};
int n = arr.length;
for (int width = 1; width < n; width *= 2) { // run length doubles each round: 1, 2, 4, ...
for (int left = 0; left < n - width; left += 2 * width) {
int mid = left + width - 1;
int right = Math.min(left + 2 * width - 1, n - 1); // last run may be shorter
merge(arr, left, mid, right);
}
}
System.out.println(Arrays.toString(arr));
}
static void merge(int[] arr, int left, int mid, int right) {
int[] leftPart = Arrays.copyOfRange(arr, left, mid + 1);
int[] rightPart = Arrays.copyOfRange(arr, mid + 1, right + 1);
int i = 0, j = 0, k = left;
while (i < leftPart.length && j < rightPart.length) {
arr[k++] = leftPart[i] <= rightPart[j] ? leftPart[i++] : rightPart[j++];
}
while (i < leftPart.length) arr[k++] = leftPart[i++];
while (j < rightPart.length) arr[k++] = rightPart[j++];
}
}
Output
Core Logic
The recursion can be dropped entirely by starting from the bottom: treat every element as a sorted run of length 1, merge neighbouring runs into runs of 2, then 4, and so on.
- 1The outer loop doubles
widtheach round: 1, 2, 4, … - 2The inner loop steps through the array in blocks of
2 * width, merging the two runs in each block. - 3
Math.min(left + 2 * width - 1, n - 1)trims the last block so a shorter final run is handled correctly. - 4The same
mergehelper as the recursive version does the actual combining.
Key Point: Avoiding recursion removes the call stack overhead and any risk of deep recursion, while keeping the same O(n log n) running time and stability.
Why: There are about log n doubling rounds, each merging all n elements, and merges still copy halves into temporary arrays.
Key Concepts
Interview Questions
Why does merge sort need extra memory?
Merging two sorted halves needs somewhere to hold one or both halves while the result is written back, which costs O(n) extra space.
Where is merge sort used in Java?
Arrays.sort on object arrays and Collections.sort use TimSort, a merge-sort variant, because it's stable.