The Merge Sort algorithm is an efficient, comparison-based sorting algorithm. It is a prime example of the Divide and Conquer algorithmic paradigm, offering a reliable time complexity across all cases, making it highly valuable for sorting large datasets.
The Divide and Conquer paradigm is a powerful problem-solving strategy that involves three main steps:
This approach often leads to recursive algorithms. The time complexity of many divide-and-conquer algorithms is given by recurrence relations of the form:
Where is the time to solve a problem of size , is the number of subproblems, is the size of each subproblem, and is the time to divide the problem and combine the subproblem solutions.
Merge Sort applies the divide and conquer strategy to the sorting problem. Given an unsorted array of elements, the goal is to sort them in non-decreasing order.
The array A[p...r] is divided into two sub-arrays: A[p...q] and A[q+1...r], where is the midpoint of the array, typically . This division continues recursively until sub-arrays contain only one element. A single-element array is inherently sorted, forming the base case for the recursion.
Each of the two sub-arrays is sorted recursively using Merge Sort itself. This means calling mergeSort on A[p...q] and mergeSort on A[q+1...r].
This is the crucial step where two sorted sub-arrays are merged into a single, larger sorted array. This process involves comparing elements from the two sub-arrays and placing them into a temporary auxiliary array in sorted order. Once all elements are placed, the sorted auxiliary array is copied back into the original array segment.
Consider two sorted sub-arrays L and R. The merging process works as follows:
i for L, j for R, and k for the merged output array.L[i] and R[j]. The smaller element is placed into arr[k], and its respective pointer (i or j) is incremented, along with k.This merge operation takes time, where is the total number of elements in the two sub-arrays being merged.
Let's sort the array [8, 2, 9, 4, 5, 3, 1, 6] using Merge Sort:
Input: [8, 2, 9, 4, 5, 3, 1, 6]
/ \
[8, 2, 9, 4] [5, 3, 1, 6] (Divide into halves)
/ \ / \
[8, 2] [9, 4] [5, 3] [1, 6] (Further divide)
/ \ / \ / \ / \
[8] [2] [9] [4] [5] [3] [1] [6] (Base cases: single elements are sorted)
\ / \ / \ / \ /
[2, 8] [4, 9] [3, 5] [1, 6] (Merge sorted pairs: (8,2)->(2,8), (9,4)->(4,9) etc.)
\ / \ /
[2, 4, 8, 9] [1, 3, 5, 6] (Merge sorted halves: (2,8,4,9)->(2,4,8,9), (3,5,1,6)->(1,3,5,6))
\ /
[1, 2, 3, 4, 5, 6, 8, 9] (Final merged sorted array)Here's a C++ implementation of the Merge Sort algorithm:
#include <iostream>
#include <vector>
#include <algorithm> // Not strictly needed for this basic implementation, but useful for other operations
// Function to merge two sorted sub-arrays
void merge(std::vector<int>& arr, int left, int mid, int right) {
int n1 = mid - left + 1; // Size of the first sub-array
int n2 = right - mid; // Size of the second sub-array
// Create temporary arrays to hold the sub-arrays
std::vector<int> L(n1);
std::vector<int> R(n2);
// Copy data from the main array to the temporary arrays
for
The time complexity of Merge Sort can be derived using a recurrence relation:
Thus, the recurrence relation for Merge Sort is:
Applying the Master Theorem (Case 2, where , , and ), the solution is:
This complexity holds true for the best, average, and worst-case scenarios, which is a significant advantage over algorithms like Quick Sort (which can degrade to in the worst case).
Merge Sort requires an auxiliary array for the merging process. In the typical implementation, this temporary array has a size proportional to the input array size. Hence, its space complexity is . This makes it not an in-place sorting algorithm.
Merge Sort is a stable sorting algorithm. This means that if two elements have equal values, their relative order in the input array is preserved in the sorted output. This property is particularly useful in scenarios where elements have associated data and their original order matters for equal keys. The L[i] <= R[j] comparison in the merge function ensures this stability.
Advantages:
Disadvantages:
An algorithmic strategy that breaks a problem into smaller sub-problems, solves them recursively, and then combines their solutions to solve the original problem.
A fundamental programming technique where a function calls itself, often breaking down a problem into smaller, similar sub-problems until a base case is reached.
The process in Merge Sort of combining two already sorted sub-arrays into a single, larger sorted array, which is the core operation of the 'Combine' step.
Merge Sort consistently achieves this optimal time complexity across best, average, and worst-case scenarios, making it very efficient for large datasets.
A sorting algorithm is stable if it preserves the relative order of equal elements in the input array. Merge Sort is a stable sorting algorithm.
Test your understanding with 5 questions
Which algorithmic paradigm does Merge Sort primarily utilize?
What is the time complexity of Merge Sort in the worst-case scenario for an array of $N$ elements?
What is the primary operation performed in the 'Combine' step of the Merge Sort algorithm?
Which of the following is a characteristic of Merge Sort?
If the recurrence relation for an algorithm is $T(n) = 2T(n/2) + \Theta(n)$, which of the following algorithms does this typically represent?
6 Modules
6 Modules