Merge Sort

Merge Sort
- Merge Sort is an array sorting algorithm based on the divide and conquer strategy.
- Merge Sort begins by splitting the array into two halves (sub-arrays) and continues splitting recursively till a sub-array is reduced to a single element, after which merging begins.
- During the merge operation, the sub-arrays are merged in sorted order into an auxiliary array.

Algorithm

1.  Split the array all the way down until each sub-array contains a single element. The splitting operation makes use of recursion and continues as recursion progresses.

MergeSort ( array, low, high )

1.  If ( low < high ) then
2.      mid = ( low + high ) / 2
3.      Recursively split the left half : MergeSort ( array, low, mid )
4.      Recursively split the right half : MergeSort ( array, mid + 1, high )
5.      Merge ( array, low, mid, high )

2.  Merge the sub-arrays into a bigger sorted sub-array using additional space. The merging operation happens during the way out of the recursion stack and requires an additional array for merging.

Merge ( array, low, mid, high )

1.   While the left sub-array i.e array [ low : mid ] and the right sub-array i.e [ mid + 1 : high ] are not empty. do
2.       Pick the smaller number at the front of either of the two sub-arrays and place this number in the auxiliary array.
3.   If there are still numbers left in the left sub-array, then add them to the auxiliary array.
4.   If there are still numbers left in the right sub-array, then add them to the auxiliary array.
5.   Copy the ( sorted ) numbers from the auxiliary array back to the original array.


Example Merge Sort


Time complexity : O ( n log ( n ) ). The time complexity of merging two sorted sub-arrays each of length n is 2n. Since merging happens at each level during the way out, the time complexity is O ( n ) * (number of levels) i.e log ( n ). Thus the complexity of merge sort is O ( n log ( n ) )

Space complexity : O ( n ), as an auxiliary array is needed for merging the sub-arrays.



Program for sorting an array using Merge Sort

from typing import List # For annotations

# Function to merge the sorted sub-arrays into a bigger array.
def Merge (aux_array : List[int], array : List[int], low : int, mid : int, high : int):

    left_index = low
    right_index = mid + 1
    aux_index = low

    # Merge elements from array[low : mid] and array[mid+1 : high]
    #                           ^                     ^
    #                           |                     |
    #                         left_index         right_index

    # Pick the smaller number between the left part and the right part
    while (left_index <= mid and right_index <= high):
        if (array[left_index] <= array[right_index]):
            aux_array[aux_index] = array[left_index]
            aux_index += 1
            left_index += 1
        else:
            aux_array[aux_index] = array[right_index]
            aux_index += 1
            right_index += 1

    if (left_index <= mid):
        # There are still some unpicked numbers in the left part
        for i in range(left_index, mid + 1):
            aux_array[aux_index] = array[i]
            aux_index += 1
    else:
        # There are still some unpicked numbers in the right part
        for i in range(right_index, high + 1):
            aux_array[aux_index] = array[i]
            aux_index += 1

    # Copy numbers from the sorted auxiliary array into the original array
    for i in range(low, high + 1):
        array[i] = aux_array[i]

# MergeSort function splits each sub-array till only a single element is available in the sub-array 
# and then proceeds with the merge of the sub-arrays into a bigger auxiliary array.
def MergeSort (aux_array : List[int], array : List[int], low : int, high : int):

    if (low < high):

       mid = int((low + high)/2)

       MergeSort (aux_array, array, low, mid)    # Recursively splits left half of the array
       MergeSort (aux_array, array, mid+1, high) # Recursively splits right half of the array

       Merge (aux_array, array, low, mid, high)  # Merge left and right half of the array keeping it sorted.

def main():

    array = [7, 3, 5, 2, 4, 1, 8, 6, 0, 10, 9]
    print("Unsorted array: " + str(array))

    # Allocate space for the auxiliary vector
    aux_array = [None] * len(array)

    MergeSort (aux_array, array, 0, len(array)-1)

    print("Sorted array using merge sort: " + str(array))

if __name__ == "__main__" :
    main()

Output

Unsorted array: [7, 3, 5, 2, 4, 1, 8, 6, 0, 10, 9]
Sorted array using merge sort: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#include<iostream>
#include<vector>

std :: vector<int> auxvec;

// Function to merge the sorted sub-arrays into a bigger array.
void Merge (std :: vector<int>& vec, int low, int mid, int high) {

    int left_index = low;
    int right_index = mid+1;
    int aux_index = low;

    /* Merge elements from vec[low : mid] and vec[mid+1 : high]
                                ^                  ^
                                |                  |
                              left_index       right_index    */

    // Pick the smaller number between the left part and the right part
    while (left_index <= mid and right_index <= high) {
       if (vec[left_index] <= vec[right_index]) {
          auxvec[aux_index++] = vec[left_index++];
       } else {
          auxvec[aux_index++] = vec[right_index++];
       }
    }

    if (left_index <= mid) {
       // There are still some unpicked numbers in the left part
       for (int i = left_index; i <= mid; i++) {
           auxvec[aux_index++] = vec[i];
       }
    } else {
       // There are still some unpicked numbers in the right part
       for (int i = right_index; i <= high; i++) {
           auxvec[aux_index++] = vec[i];
       }
    }

    // Copy numbers from the sorted auxiliary vector into the original vector
    for (int i=low; i<=high; i++) {
        vec[i] = auxvec[i];
    }
}

// MergeSort function splits each sub-array till only a single element is available in the sub-array 
// and then proceeds with the merge of the sub-arrays into a bigger auxiliary array.
void MergeSort (std :: vector<int>& vec, int low, int high) {

    int mid;
    if (low < high) {
       mid = (low + high)/2;
       MergeSort (vec, low, mid); // Recursively splits left half of the array
       MergeSort (vec, mid+1, high); // Recursively splits right half of the array
       Merge (vec, low, mid, high); // Merge left and right half of the array keeping it sorted.
    }
}

int main(){

    std :: vector<int> vec = {7, 3, 5, 2, 4, 1, 8, 6};
    // Allocate space for the auxiliary vector
    auxvec.resize(vec.size());
    MergeSort (vec, 0, vec.size()-1);

    std :: cout << "Sorted numbers : ";
    for (auto& it: vec)
        std :: cout << it << " ";
    return 0;
}

Output

Sorted numbers : 1 2 3 4 5 6 7 8
class Sort {

    private int[] aux_array;

    // Allocate space to auxiliary array which is to be used for merging the sorted elements
    Sort (int sz) {
        aux_array = new int[sz];
    }

    // Function to merge the sorted sub-arrays into a bigger array.
    //void Merge (int[] aux_array, int[] array, int low, int mid, int high) {
    void Merge (int[] array, int low, int mid, int high) {

        int left_index = low;
        int right_index = mid+1;
        int aux_index = low;

        /* Merge elements from array[low : mid] and array[mid+1 : high]
                                      ^                     ^
                                      |                     |
                                  left_index         right_index */

        // Pick the smaller number between the left part and the right part
        while (left_index <= mid && right_index <= high) {
           if (array[left_index] <= array[right_index]) {
              aux_array[aux_index++] = array[left_index++];
           } else {
              aux_array[aux_index++] = array[right_index++];
           }
        }

        if (left_index <= mid) {
           // There are still some unpicked numbers in the left part
           for (int i = left_index; i <= mid; i++) {
               aux_array[aux_index++] = array[i];
           }
        } else {
           // There are still some unpicked numbers in the right part
           for (int i = right_index; i <= high; i++) {
               aux_array[aux_index++] = array[i];
           }
        }

        // Copy numbers from the sorted auxiliary array into the original array
        for (int i=low; i<=high; i++) {
            array[i] = aux_array[i];
        }
    }

    // MergeSort function splits each sub-array till only a single element is available in the sub-array 
    // and then proceeds with the merge of the sub-arrays into a bigger auxiliary array.
    //void MergeSort (int[] aux_array, int[] array, int low, int high) {
    void MergeSort (int[] array, int low, int high) {

        int mid;
        if (low < high) {
           mid = (low + high)/2;
           MergeSort (array, low, mid); // Recursively splits left half of the array
           MergeSort (array, mid + 1, high); // Recursively splits right half of the array
           Merge (array, low, mid, high); // Merge left and right half of the array keeping it sorted.
        }
    }

    public static void main (String[] args) {

        int[] array = {7, 3, 5, 2, 4, 1, 8, 6};
        //int[] aux_array = new int[array.length];

        System.out.print("Unsorted array: ");

        for (int i=0; i<array.length; i++)
            System.out.print(array[i] + " ");
        System.out.println();

        Sort s = new Sort(array.length);
        s.MergeSort (array, 0, array.length-1);

        System.out.print("Sorted array using Merge-Sort: ");

        for (int i=0; i<array.length; i++)
            System.out.print(array[i] + " ");
    }
}

Output

Unsorted array: 7 3 5 2 4 1 8 6 
Sorted array using Merge-Sort: 1 2 3 4 5 6 7 8



Copyright (c) 2019-2022, Algotree.org.
All rights reserved.