# Merge Sort Algorithm

^{2}) while heap sort, merge sort and quicksort (with some assumptions) have complexity of O(nlogn) and count and Radix sorts are linear O(n) algorithms.

**Merge sort**falls in divide and conquer class of algorithm where input space is divided into subproblems and these subproblems are then solved individually and combined together to give solution to the original problem. Below figure explains divide and conquer paradigm.

If don’t want to read, watch merge sort video

**Merge sort implementation**

**Code explanation**

For

*mergesort*function we get three parameters, the input array

*a[], the start index and the end*index of array. This start and end change in every recursive invocation of mergesort function.

We find the middle index using start and end index of the input array and again invoke the same function with two parts one starting from start to mid and other being from mid+1 to end.

Once base condition is hit, we start winding up and call merge function.

*Merge*function takes four parameters,

*input array, start, end and middle index*based on start and end.

Merge function merges two sub arrays (one from start to mid and other from mid+1 to end) into a single array from start to end. This array is then returned to upper calling function which then again sort two parts of array.

**Complexity analysis**

As we know that every time input space is divided into two and from the binary search algorithm we know that this division will have complexity of O(log n) where n is input size. So the first part of implementation of merge sort has complexity of O(logn). Now the second part of implements merge step which place every elements in its proper place in array, hence it linear time O(n). Since above step of dividing has to be done for n elements, hence total complexity of merge sort will be O(nlogn).

There are some improvements which can be done on this algorithm.

1. When number of elements are less than some threshold, one can use insertion or selection sort to sort those numbers. Why? Because when n is small, O(n^{2}) is as good as O(nlogn) and it saves extra overhead of split and merging. All in all, using insertion sort in input array with small size, can give better performance.

2. Before calling merging, check if all the elements in right array are greater then left array, if yes, no need of merging. This can be easily checked by comparing *a[mid]* with *a[mid+1]*. If *a[mid]* is less than *a[mid+1]*, two sub arrays are already sorted and we don’t need to perform merge.

**External Merge sort**

Merge sort is best used when data is in huge in size as compared to available memory, like sorting 2GB of data when we have only 100 MB of RAM or physical memory. Data cannot fit in memory and resides on to disk from where it is fetched in chunks and merged.

There are two passes in the external merge sort : Sort pass and merge pass. below figure explains this

**Sort pass**

- Divide the input in N chunks where N = Size of total data/Size of available memory
- Load each chunk in main memory and sort it with any conventional sorting algorithm.
- Now load a predefined block of the sorted chunks into memory again. keep a buffer to store sorted output.

**Merge Pass**

- Now have N-way merge and put output on to buffer. As buffer get full, write that onto disk.
- If any of the small chunk taken if exhausted, one can fill the next block from the same chunk.

External merge sort can be improved significantly using parallelism where data chunks are written on different disk where read and write can be performed in parallel. Also, different chunk can be sorted on different processors in parallel. If processors are not available, merge routine can take advantage of multithreading.

There is one problem which is classic example of usage of external merge sort is mentioned here in problem number 5 and solved here : External merge sort.

If you have any other optimization trick or better way to implement merge sort please comment below.