Given an array of integers, nums,sort the array in non-decreasing order using the merge sort algorithm. Return the sorted array.
A sorted array in non-decreasing order is one in which each element is either greater than or equal to all the elements to its left in the array.
Input: nums = [7, 4, 1, 5, 3]
Output: [1, 3, 4, 5, 7]
Explanation: 1 <= 3 <= 4 <= 5 <= 7.
Thus the array is sorted in non-decreasing order.
Input: nums = [5, 4, 4, 1, 1]
Output: [1, 1, 4, 4, 5]
Explanation: 1 <= 1 <= 4 <= 4 <= 5.
Thus the array is sorted in non-decreasing order.
Input: nums = [3, 2, 3, 4, 5]
Merge Sort is a powerful sorting algorithm that follows the divide-and-conquer approach. The array is divided into two equal halves until each sub-array contains only one element. Each pair of smaller sorted arrays is then merged into a larger sorted array.
The algorithm consists of two main functions:
By repeating these steps recursively, Merge Sort efficiently sorts the entire array.
To implement Merge Sort, we will create two functions: mergeSort()
and merge()
.
mergeSort(arr[], low, high)
mergeSort()
, divide the array around the middle index by making recursive calls: mergeSort(arr, low, mid)
for the left half and mergeSort(arr, mid+1, high)
for the right half. Here, low
is the leftmost index, high
is the rightmost index, and mid
is the middle index of the array.low
and high
are the same, pointing to a single element. If low >= high
, the function returns.merge(arr[], low, mid, high)
low
to mid
and the range of the right half is from mid+1
to high
.left
starting from low
and right
starting from mid+1
. Using a while loop (while left <= mid && right <= high
), compare the elements from each half and insert the smaller one into the temporary array. After the loop, any leftover elements in both halves are copied into the temporary array.low
to high
.This approach ensures that the array is efficiently sorted using the divide-and-conquer strategy of Merge Sort.
<!---<img src="https://static.takeuforward.org/premium/Sorting/Algorithms/Merge Sorting/MergeSort-0ZYzA6GX" alt="Merge Sort Illustration ">---!>#include <bits/stdc++.h>
using namespace std;
class Solution{
public:
// Function to merge two sorted halves of the array
void merge(vector<int> &arr, int low, int mid, int high) {
// Temporary array to store merged elements
vector<int> temp;
int left = low;
int right = mid + 1;
// Loop until subarrays are exhausted
while (left <= mid && right <= high) {
// Compare left and right elements
if (arr[left] <= arr[right]) {
// Add left element to temp
temp.push_back(arr[left]);
// Move left pointer
left++;
}
else {
// Add right element to temp
temp.push_back(arr[right]);
// Move right pointer
right++;
}
}
// Adding the remaining elements of left half
while (left <= mid) {
temp.push_back(arr[left]);
left++;
}
// Adding the remaining elements of right half
while (right <= high) {
temp.push_back(arr[right]);
right++;
}
// Transferring the sorted elements to arr
for (int i = low; i <= high; i++) {
arr[i] = temp[i - low];
}
}
// Helper function to perform merge sort from low to high
void mergeSortHelper(vector<int> &arr, int low, int high){
// Base case: if the array has only one element
if (low >= high)
return;
// Find the middle index
int mid = (low + high) / 2;
// Recursively sort the left half
mergeSortHelper(arr, low, mid);
// Recursively sort the right half
mergeSortHelper(arr, mid + 1, high);
// Merge the sorted halves
merge(arr, low, mid, high);
}
// Function to perform merge sort on the given array
vector<int> mergeSort(vector<int> &nums) {
int n = nums.size(); // SIze of array
// Perform Merge sort on the whole array
mergeSortHelper(nums, 0, n-1);
// Return the sorted array
return nums;
}
};
int main(){
vector<int> arr = {9, 4, 7, 6, 3, 1, 5};
int n = arr.size();
cout << "Before Sorting Array: " << endl;
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
// Create an instance of the Solution class
Solution sol;
// Function call to sort the array
vector<int> sortedArr = sol.mergeSort(arr);
cout << "After Sorting Array: " << endl;
for (int i = 0; i < n; i++)
cout << sortedArr[i] << " ";
cout << endl;
return 0;
}
import java.util.*;
class Solution {
// Function to merge two sorted halves of the array
public void merge(int[] arr, int low, int mid, int high) {
// Temporary array to store merged elements
List<Integer> temp = new ArrayList<>();
int left = low;
int right = mid + 1;
// Loop until subarrays are exhausted
while (left <= mid && right <= high) {
// Compare left and right elements
if (arr[left] <= arr[right]) {
// Add left element to temp
temp.add(arr[left]);
// Move left pointer
left++;
} else {
// Add right element to temp
temp.add(arr[right]);
// Move right pointer
right++;
}
}
// Adding the remaining elements of left half
while (left <= mid) {
temp.add(arr[left]);
left++;
}
// Adding the remaining elements of right half
while (right <= high) {
temp.add(arr[right]);
right++;
}
// Transferring the sorted elements to arr
for (int i = low; i <= high; i++) {
arr[i] = temp.get(i - low);
}
}
// Helper function to perform merge sort from low to high
public void mergeSortHelper(int[] arr, int low, int high) {
// Base case: if the array has only one element
if (low >= high)
return;
// Find the middle index
int mid = (low + high) / 2;
// Recursively sort the left half
mergeSortHelper(arr, low, mid);
// Recursively sort the right half
mergeSortHelper(arr, mid + 1, high);
// Merge the sorted halves
merge(arr, low, mid, high);
}
// Function to perform merge sort on the given array
public int[] mergeSort(int[] nums) {
int n = nums.length; // Size of array
// Perform Merge sort on the whole array
mergeSortHelper(nums, 0, n - 1);
// Return the sorted array
return nums;
}
}
public class Main {
public static void main(String[] args) {
int[] arr = {9, 4, 7, 6, 3, 1, 5};
int n = arr.length;
System.out.println("Before Sorting Array: ");
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
System.out.println();
// Create an instance of the Solution class
Solution sol = new Solution();
// Function call to sort the array
int[] sortedArr = sol.mergeSort(arr);
System.out.println("After Sorting Array: ");
for (int i = 0; i < n; i++)
System.out.print(sortedArr[i] + " ");
System.out.println();
}
}
class Solution:
# Function to merge two sorted halves of the array
def merge(self, arr, low, mid, high):
# Temporary array to store merged elements
temp = []
left = low
right = mid + 1
# Loop until subarrays are exhausted
while left <= mid and right <= high:
# Compare left and right elements
if arr[left] <= arr[right]:
# Add left element to temp
temp.append(arr[left])
# Move left pointer
left += 1
else:
# Add right element to temp
temp.append(arr[right])
# Move right pointer
right += 1
# Adding the remaining elements of left half
while left <= mid:
temp.append(arr[left])
left += 1
# Adding the remaining elements of right half
while right <= high:
temp.append(arr[right])
right += 1
# Transferring the sorted elements to arr
for i in range(low, high + 1):
arr[i] = temp[i - low]
# Helper function to perform merge sort from low to high
def mergeSortHelper(self, arr, low, high):
# Base case: if the array has only one element
if low >= high:
return
# Find the middle index
mid = (low + high) // 2
# Recursively sort the left half
self.mergeSortHelper(arr, low, mid)
# Recursively sort the right half
self.mergeSortHelper(arr, mid + 1, high)
# Merge the sorted halves
self.merge(arr, low, mid, high)
# Function to perform merge sort on the given array
def mergeSort(self, nums):
n = len(nums) # Size of array
# Perform Merge sort on the whole array
self.mergeSortHelper(nums, 0, n - 1)
# Return the sorted array
return nums
if __name__ == "__main__":
arr = [9, 4, 7, 6, 3, 1, 5]
n = len(arr)
print("Before Sorting Array: ")
for i in range(n):
print(arr[i], end=" ")
print()
# Create an instance of the Solution class
sol = Solution()
# Function call to sort the array
sortedArr = sol.mergeSort(arr)
print("After Sorting Array: ")
for i in range(n):
print(sortedArr[i], end=" ")
print()
class Solution {
// Function to merge two sorted halves of the array
merge(arr, low, mid, high) {
// Temporary array to store merged elements
let temp = [];
let left = low;
let right = mid + 1;
// Loop until subarrays are exhausted
while (left <= mid && right <= high) {
// Compare left and right elements
if (arr[left] <= arr[right]) {
// Add left element to temp
temp.push(arr[left]);
// Move left pointer
left++;
} else {
// Add right element to temp
temp.push(arr[right]);
// Move right pointer
right++;
}
}
// Adding the remaining elements of left half
while (left <= mid) {
temp.push(arr[left]);
left++;
}
// Adding the remaining elements of right half
while (right <= high) {
temp.push(arr[right]);
right++;
}
// Transferring the sorted elements to arr
for (let i = low; i <= high; i++) {
arr[i] = temp[i - low];
}
}
// Helper function to perform merge sort from low to high
mergeSortHelper(arr, low, high) {
// Base case: if the array has only one element
if (low >= high)
return;
// Find the middle index
let mid = Math.floor((low + high) / 2);
// Recursively sort the left half
this.mergeSortHelper(arr, low, mid);
// Recursively sort the right half
this.mergeSortHelper(arr, mid + 1, high);
// Merge the sorted halves
this.merge(arr, low, mid, high);
}
// Function to perform merge sort on the given array
mergeSort(nums) {
let n = nums.length; // Size of array
// Perform Merge sort on the whole array
this.mergeSortHelper(nums, 0, n - 1);
// Return the sorted array
return nums;
}
}
const main = () => {
let arr = [9, 4, 7, 6, 3, 1, 5];
let n = arr.length;
console.log("Before Sorting Array: ");
for (let i = 0; i < n; i++)
process.stdout.write(arr[i] + " ");
console.log();
// Create an instance of the Solution class
let sol = new Solution();
// Function call to sort the array
let sortedArr = sol.mergeSort(arr);
console.log("After Sorting Array: ");
for (let i = 0; i < n; i++)
process.stdout.write(sortedArr[i] + " ");
console.log();
}
// Execute the main function
main();
Time Complexity: O(nlogn). At each step, we divide the whole array, which takes logn steps, and we assume n steps are taken to sort the array. So, the overall time complexity is nlogn.
Space Complexity: O(n). We are using a temporary array to store elements in sorted order.
Q: Why does merge sort require extra space, and how much?
A: Merge sort requires extra space to store temporary arrays during the merge process. At each step, two halves are merged into a temporary array before copying back into the original array. The space complexity is O(n), where n is the size of the input array. Example: Input: [4, 3, 2, 1] Merge process uses temporary arrays to combine [4, 3] and [2, 1] into sorted halves, and finally merges them into [1, 2, 3, 4].
Q: Can merge sort handle duplicate elements?
A: Yes, merge sort naturally handles duplicates by preserving their relative order during the merging process. This makes it a stable sorting algorithm.
Q: Can merge sort be implemented in-place? If not, why?
A: Standard merge sort is not in-place because merging two sorted arrays requires additional memory to combine them. However, there are in-place variations of merge sort, but they are complex and trade simplicity and performance for reduced memory usage.
Q: Why is merge sort preferred for linked lists?
A: Linked lists do not support random access, making quicksort inefficient. Merge sort efficiently splits linked lists into halves using pointers without needing extra space for copying. Merging two sorted linked lists can be done in O(n) without additional memory overhead. Example: Input: 4 → 2 → 9 → 1 Process: Split into 4 → 2 and 9 → 1. Sort each half: 2 → 4 and 1 → 9. Merge: 1 → 2 → 4 → 9.