Open In App

Can we improve the performance of a merge sort algorithm?

Last Updated : 18 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

The merge sort, in essence, is a divide-and-conquer algorithm. It breaks down a problem into multiple sub-problems, solves each individually, and finally combines these sub-problems solutions to form the final solution.

The key operation in merge sort is the merging step. This step is where the algorithm compares and combines the individual elements of the sublists. It takes advantage of the fact that each of the sublists is already sorted. The merging process continues until there is only one sorted list remaining.

This methodological partitioning allows for efficient sorting, even in large datasets.

The algorithm can be divided into two main steps:

  • Divide: The divide step computes the midpoint of the indices, taking constant time regardless of the subarray size.
  • Conquer (Merge): The conquer step recursively sorts two subarrays of approximately n/2 elements each. The time this step takes will be considered when we account for the subproblems. The combined step merges a total of n elements, taking Θ(n) time. This step is where the ‘merge’ in merge sort comes from.

Overall time complexity of Merge sort is O(nLogn).

Optimizing Merge Sort:

The Fusion of Merge Sort and Insertion Sort for Optimal Performance.

  • We can cut the running time of merge sort substantially with some carefully considered modifications to the implementation.
  • Use insertion sort for small subarrays. We can improve most recursive algorithms by handling small cases differently. Switching to insertion sort for small subarrays will improve the running time of a typical merge sort.
  • This is because insertion sort, while worse in the long run, performs faster on small input sizes. Changing the base case of your merge sort so that if the array to sort is below a certain size threshold (say, 50–100), you switch to insertion sort, which can markedly improve the performance of the algorithm.

Why insertion sort for smaller dataset better than merge sort?

Insertion sort is often considered more efficient than merge sort for smaller datasets due to its lower overhead and simpler implementation. Time complexity of insertion sort is O(n^2) but for small datasets, the quadratic time complexity doesn’t impose a significant overhead thus, O(n^2)~ O(n), and the simplicity of the algorithm makes it efficient. While merge sort involves more complex operations and has higher space requirements.

Implementation of merge sort with insertion sort for better complexity and optimal performance.

C++




#include <iostream>
#include <vector>
using namespace std;
 
// Merge two subarrays into array
void merge(vector<int>& array, int p, int q, int r) {
    // Calculate the sizes of the two subarrays
    int n1 = q - p + 1;
    int n2 = r - q;
 
    // Create temporary vectors to hold the two subarrays
    vector<int> leftArray(n1);
    vector<int> rightArray(n2);
 
    // Copy data to temporary vectors leftArray[] and rightArray[]
    for (int i = 0; i < n1; ++i) {
        leftArray[i] = array[p + i];
    }
    for (int j = 0; j < n2; ++j) {
        rightArray[j] = array[q + 1 + j];
    }
 
    // Merge the two subarrays back into the original array
    int i = 0; // Initial index of first subarray
    int j = 0; // Initial index of second subarray
    int k = p; // Initial index of merged subarray
 
    while (i < n1 && j < n2) {
        if (leftArray[i] <= rightArray[j]) {
            array[k] = leftArray[i];
            ++i;
        } else {
            array[k] = rightArray[j];
            ++j;
        }
        ++k;
    }
 
    // Copy the remaining elements of leftArray[], if there are any
    while (i < n1) {
        array[k] = leftArray[i];
        ++i;
        ++k;
    }
 
    // Copy the remaining elements of rightArray[], if there are any
    while (j < n2) {
        array[k] = rightArray[j];
        ++j;
        ++k;
    }
}
 
// Divide the vector into two subarrays, sort them, and merge them
void mergeSort(vector<int>& array, int left, int right) {
    if (left < right) {
        // m is the point where the array is divided into two subarrays
        int mid = (left + right) / 2;
        // recursive calls to each subarray
        mergeSort(array, left, mid);
        mergeSort(array, mid + 1, right);
        // Merge the sorted subarrays
        merge(array, left, mid, right);
    }
}
 
int main() {
    // created an unsorted vector
    vector<int> array = {6, 5, 12, 10, 9, 1};
    // call the method mergeSort()
    mergeSort(array, 0, array.size() - 1);
 
    cout << "Sorted Array:" << endl;
    for (int num : array) {
        cout << num << " ";
    }
    cout << endl;
 
    return 0;
}


Java




import java.io.*;
import java.util.Arrays;
 
class Main {
    // Merge two subarrays into array
    void merge(int array[], int p, int q, int r)
    {
        // Calculate the sizes of the two subarrays
        int n1 = q - p + 1;
        int n2 = r - q;
 
        // Create temporary arrays to hold the two subarrays
        int[] leftArray = new int[n1];
        int[] rightArray = new int[n2];
 
        // Copy data to temporary arrays leftArray[] and
        // rightArray[]
        for (int i = 0; i < n1; ++i) {
            leftArray[i] = array[p + i];
        }
        for (int j = 0; j < n2; ++j) {
            rightArray[j] = array[q + 1 + j];
        }
 
        // Merge the two subarrays back into the original
        // array
        int i = 0; // Initial index of first subarray
        int j = 0; // Initial index of second subarray
        int k = p; // Initial index of merged subarray
 
        while (i < n1 && j < n2) {
            if (leftArray[i] <= rightArray[j]) {
                array[k] = leftArray[i];
                ++i;
            }
            else {
                array[k] = rightArray[j];
                ++j;
            }
            ++k;
        }
 
        // Copy the remaining elements of leftArray[], if
        // there are any
        while (i < n1) {
            array[k] = leftArray[i];
            ++i;
            ++k;
        }
 
        // Copy the remaining elements of rightArray[], if
        // there are any
        while (j < n2) {
            array[k] = rightArray[j];
            ++j;
            ++k;
        }
    }
 
    // Divide the array into two subarrays, sort them, and
    // merge them
    void mergeSort(int array[], int left, int right)
    {
        if (left < right) {
            // m is the point where the array is divided
            // into two subarrays
            int mid = (left + right) / 2;
            // recursive calls to each subarray
            mergeSort(array, left, mid);
            mergeSort(array, mid + 1, right);
            // Merge the sorted subarrays
            merge(array, left, mid, right);
        }
    }
 
    public static void main(String args[])
    {
        // created an unsorted array
        int[] array = { 6, 5, 12, 10, 9, 1 };
        Main ob = new Main();
        // call the method mergeSort()
        ob.mergeSort(array, 0, array.length - 1);
        System.out.println("Sorted Array:");
        System.out.println(Arrays.toString(array));
    }
}


Python3




# Merge two subarrays into array
def merge(array, p, q, r):
    # Calculate the sizes of the two subarrays
    n1 = q - p + 1
    n2 = r - q
 
    # Create temporary lists to hold the two subarrays
    left_array = array[p:p + n1]
    right_array = array[q + 1:q + 1 + n2]
 
    # Merge the two subarrays back into the original array
    i = j = 0
    k = p
 
    while i < n1 and j < n2:
        if left_array[i] <= right_array[j]:
            array[k] = left_array[i]
            i += 1
        else:
            array[k] = right_array[j]
            j += 1
        k += 1
 
    # Copy the remaining elements of left_array[], if any
    while i < n1:
        array[k] = left_array[i]
        i += 1
        k += 1
 
    # Copy the remaining elements of right_array[], if any
    while j < n2:
        array[k] = right_array[j]
        j += 1
        k += 1
 
 
# Divide the list into two subarrays, sort them, and merge them
def merge_sort(array, left, right):
    if left < right:
        # m is the point where the array is divided into two subarrays
        mid = (left + right) // 2
        # recursive calls to each subarray
        merge_sort(array, left, mid)
        merge_sort(array, mid + 1, right)
        # Merge the sorted subarrays
        merge(array, left, mid, right)
 
 
if __name__ == "__main__":
    # Create an unsorted list
    array = [6, 5, 12, 10, 9, 1]
    # Call the method merge_sort()
    merge_sort(array, 0, len(array) - 1)
 
    print("Sorted Array:")
    for num in array:
        print(num, end=" ")
    print()
 
 
# This code is contributed by rambabuguphka


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Merge two subarrays into array
    static void Merge(List<int> array, int p, int q, int r)
    {
        int n1 = q - p + 1;
        int n2 = r - q;
 
        List<int> leftArray = new List<int>(n1);
        List<int> rightArray = new List<int>(n2);
 
        for (int x = 0; x < n1; ++x)
        {
            leftArray.Add(array[p + x]);
        }
 
        for (int y = 0; y < n2; ++y)
        {
            rightArray.Add(array[q + 1 + y]);
        }
 
        int i = 0, j = 0;
        int k = p;
 
        while (i < n1 && j < n2)
        {
            if (leftArray[i] <= rightArray[j])
            {
                array[k] = leftArray[i];
                ++i;
            }
            else
            {
                array[k] = rightArray[j];
                ++j;
            }
            ++k;
        }
 
        while (i < n1)
        {
            array[k] = leftArray[i];
            ++i;
            ++k;
        }
 
        while (j < n2)
        {
            array[k] = rightArray[j];
            ++j;
            ++k;
        }
    }
 
    // Divide the vector into two subarrays, sort them, and merge them
    static void MergeSort(List<int> array, int left, int right)
    {
        if (left < right)
        {
            int mid = (left + right) / 2;
 
            MergeSort(array, left, mid);
            MergeSort(array, mid + 1, right);
 
            Merge(array, left, mid, right);
        }
    }
 
    static void Main(string[] args)
    {
        List<int> array = new List<int> { 6, 5, 12, 10, 9, 1 };
 
        MergeSort(array, 0, array.Count - 1);
 
        Console.WriteLine("Sorted Array:");
        foreach (int num in array)
        {
            Console.Write(num + " ");
        }
        Console.WriteLine();
    }
}
 
// This code is contributed by shivamgupta0987654321


Javascript




// Javascript Implementation
 
// Function to merge two subarrays into the main array
function merge(array, p, q, r) {
    let n1 = q - p + 1;
    let n2 = r - q;
 
    let leftArray = new Array(n1);
    let rightArray = new Array(n2);
 
    for (let i = 0; i < n1; ++i) {
        leftArray[i] = array[p + i];
    }
    for (let j = 0; j < n2; ++j) {
        rightArray[j] = array[q + 1 + j];
    }
 
    let i = 0, j = 0, k = p;
 
    while (i < n1 && j < n2) {
        if (leftArray[i] <= rightArray[j]) {
            array[k] = leftArray[i];
            ++i;
        } else {
            array[k] = rightArray[j];
            ++j;
        }
        ++k;
    }
 
    while (i < n1) {
        array[k] = leftArray[i];
        ++i;
        ++k;
    }
 
    while (j < n2) {
        array[k] = rightArray[j];
        ++j;
        ++k;
    }
}
 
// Function to perform merge sort
function mergeSort(array, left, right) {
    if (left < right) {
        let mid = Math.floor((left + right) / 2);
        mergeSort(array, left, mid);
        mergeSort(array, mid + 1, right);
        merge(array, left, mid, right);
    }
}
 
// Driver code
 
let array = [6, 5, 12, 10, 9, 1];
mergeSort(array, 0, array.length - 1);
 
console.log("Sorted Array:");
console.log(array.join(" "));
 
// This code is contributed by Tapesh(tapeshdua420)


Output

Sorted Array:
[1, 5, 6, 9, 10, 12]








Understanding and leveraging the merge sort algorithm can significantly enhance your code’s performance, particularly when working with large datasets.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads