Merge Sort as Divide and Conquer in DSA C++ - Time & Space Complexity
We want to understand how the time taken by merge sort changes as the list size grows.
How does splitting and merging affect the total work done?
Analyze the time complexity of the following merge sort code.
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int L[n1], R[n2];
for (int i = 0; i < n1; i++) L[i] = arr[left + i];
for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
This code splits the array into halves, sorts each half, then merges them back.
Look at the repeated actions in the code.
- Primary operation: Splitting the array and merging sorted halves.
- How many times: The array is split recursively until single elements remain, then merged back up.
Each split divides the array in half, and merging takes time proportional to the size of the current part.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 40 merges and splits combined |
| 100 | About 700 merges and splits combined |
| 1000 | About 10,000 merges and splits combined |
Pattern observation: The work grows a bit more than linearly but much less than quadratically, roughly n times log n.
Time Complexity: O(n log n)
This means the time grows proportionally to the size of the list times the number of times it can be split in half.
[X] Wrong: "Merge sort is just like bubble sort and takes quadratic time because it compares many elements."
[OK] Correct: Merge sort smartly splits the list and merges sorted parts, so it avoids repeated comparisons on the whole list, making it much faster.
Understanding merge sort's time complexity shows you can analyze divide and conquer methods, a key skill for solving many problems efficiently.
"What if we changed merge sort to split the array into three parts instead of two? How would the time complexity change?"
Practice
Merge Sort algorithm?Solution
Step 1: Understand the divide and conquer approach
Merge Sort splits the array into two halves recursively until single elements remain.Step 2: Merge sorted halves
After splitting, it merges the halves back in sorted order to form the sorted array.Final Answer:
Divide the array into halves, sort each half, then merge them -> Option CQuick Check:
Merge Sort = Divide, sort halves, merge [OK]
- Confusing Merge Sort with Bubble Sort
- Thinking Merge Sort uses a pivot like Quick Sort
- Believing Merge Sort sorts in place without merging
Solution
Step 1: Identify when to stop recursion
The base case is when the subarray has one or zero elements, meaning start index is greater or equal to end index.Step 2: Match condition to code
The conditionif (start >= end) return;correctly stops recursion when the subarray cannot be divided further.Final Answer:
if (start >= end) return; -> Option DQuick Check:
Base case = start >= end [OK]
- Using start > end misses single element subarray
- Using start == end + 1 is incorrect indexing
- Using start < end returns too early
{4, 1, 3, 2}?
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1, n2 = r - m;
int L[n1], R[n2];
for (int i = 0; i < n1; i++) L[i] = arr[l + i];
for (int j = 0; j < n2; j++) R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
void mergeSort(int arr[], int l, int r) {
if (l >= r) return;
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
int main() {
int arr[] = {4, 1, 3, 2};
int n = 4;
mergeSort(arr, 0, n - 1);
for (int i = 0; i < n; i++) std::cout << arr[i] << " ";
return 0;
}Solution
Step 1: Trace recursive splitting and merging
The array splits into [4,1] and [3,2], then further into single elements. Each pair is merged sorted: [1,4] and [2,3].Step 2: Final merge
Merging [1,4] and [2,3] results in [1,2,3,4]. The output prints this sorted array.Final Answer:
1 2 3 4 -> Option AQuick Check:
Sorted array = 1 2 3 4 [OK]
- Confusing merge order causing wrong output
- Forgetting to merge after recursive calls
- Printing array before sorting completes
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1, n2 = r - m;
int L[n1], R[n2];
for (int i = 0; i <= n1; i++) L[i] = arr[l + i];
for (int j = 0; j < n2; j++) R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}Solution
Step 1: Check loop bounds for copying left array
The loop uses 'i <= n1', which runs one extra iteration causing out-of-bounds access since valid indices are 0 to n1-1.Step 2: Correct loop condition
The loop should be 'i < n1' to copy exactly n1 elements without overflow.Final Answer:
The loop 'for (int i = 0; i <= n1; i++)' causes out-of-bounds access -> Option AQuick Check:
Loop bounds must be less than array size [OK]
- Using <= instead of < in loops
- Starting indices at 1 instead of 0
- Ignoring dynamic allocation but it's not mandatory here
{5, 3, 8, 6, 2, 7, 4, 1}, how many total merge operations will be performed during a full Merge Sort?Solution
Step 1: Understand merge operations in Merge Sort
Merge Sort splits the array until single elements, then merges pairs stepwise. For n=8 elements, merges happen at each level combining subarrays.Step 2: Calculate total merges
Number of merges = n - 1 = 8 - 1 = 7 merges in total to combine all elements into one sorted array.Final Answer:
7 -> Option BQuick Check:
Total merges = n - 1 = 7 [OK]
- Counting merges as number of elements
- Confusing merges with recursive calls
- Assuming merges double at each level
Ready to prove it?
Pass the test and this pattern moves unknown
