In-Place Merge: Analysis
Here is the in-place merge method, with the loop condition from the previous section.
public static void merge(int[] arr, int mid) {
for (int k = 0; k < mid && mid < arr.length; k++) {
// if the current element is larger than the first element of the second
// half, we need to move arr[mid] to arr[k], and shift everything from
// arr[k] to arr[mid - 1] to the right
if (arr[k] > arr[mid]) {
int temp = arr[mid];
for (int i = mid; i > k; i--) {
arr[i] = arr[i - 1];
}
arr[k] = temp;
mid++; // the boundary between the two sorted halves moves right after each insertion
}
}
}
Start with the space, because saving space is why we tried this. We are not creating a new array to hold the merged result. The only extra space is the variables k, i, and temp, and that is a constant amount no matter how long the array is, so the auxiliary space is .
Now let’s switch to time complexity. Let be the length of the input array.
- The outer loop advances
kby one each time and stops whenkreachesmid, andmidis never more than . So the outer loop runs times. - The inner loop shifts the elements at indices
kthroughmid - 1, so it runsmid - ktimes. That is at most , so the inner loop is .
Multiplying the two bounds gives as an upper bound. Now, is there an input that actually costs that much?
Yes. Take the case where every element in the second half is smaller than every element in the first half. Then arr[k] > arr[mid] is true on every iteration, so every iteration enters the inner loop and shifts. Say each half has elements. Each insertion moves both k and mid right by one, so mid - k stays at and each of the insertions shifts elements. That is about moves in total, which is .
The best case is the opposite arrangement. Every element in the first half is smaller than every element in the second half. Then arr[k] > arr[mid] is false every time. We never enter the inner loop, and the outer loop just advances k across the first half. That is .
We can do even better in that case if we add one check. If arr[mid - 1] <= arr[mid], then the largest element of the first half is no larger than the smallest element of the second half, so the array is already merged and we can return right away. If we put that check at the top of the method, the best case becomes .
Now compare that with the merge that allocates a new array. That one runs in time and auxiliary space. The in-place merge runs in auxiliary space, but its worst case is time.
That is why this simple in-place merge is not commonly used. There are more advanced in-place merge algorithms that do better, but we will not cover them in this course.