Merge Sort In Java – Program To Implement MergeSort

This Tutorial Explains what is Merge Sort in Java, MergeSort Algorithm, Pseudo Code, Merge Sort Implementation, Examples of Iterative & Recursive MergeSort:

Merge sort technique uses a “Divide-and-Conquer” strategy. In this technique, the data set that is to be sorted is divided into smaller units to sort it.

=> Read Through The Easy Java Training Series.

Merge Sort In Java

Merge Sort In Java

For example, if an array is to be sorted using mergesort, then the array is divided around its middle element into two sub-arrays. These two sub-arrays are further divided into smaller units until we have only 1 element per unit.

Once the division is done, this technique merges these individual units by comparing each element and sorting them when merging. This way by the time the entire array is merged back, we get a sorted array.

In this tutorial, we will discuss all the details of this sorting technique in general including its algorithm and pseudo codes as well as the implementation of the technique in Java.

MergeSort Algorithm In Java

Following is the algorithm for the technique.

#1) Declare an array myArray of length N

#2) Check if N=1, myArray is already sorted

#3) If N is greater than 1,

  • set left = 0, right = N-1
  • compute middle = (left + right)/2
  • Call subroutine merge_sort (myArray,left,middle) => this sorts first half of the array
  • Call subroutine merge_sort (myArray,middle+1,right) => this will sort the second half of the array
  • Call subroutine merge (myArray, left, middle, right) to merge arrays sorted in the above steps.

#4) Exit

As seen in the algorithm steps, the array is divided into two in the middle. Then we recursively sort the left half of the array and then the right half. Once we individually sort both the halves, they are merged together to obtain a sorted array.

Merge Sort Pseudo Code

Let's see the pseudo-code for the Mergesort technique. As already discussed since this is a ‘divide-and-conquer’ technique, we will present the routines for dividing the data set and then merging the sorted data sets.

procedure mergesort( var intarray as array )
   if ( n == 1 ) return intarray

   var lArray as array = intarray[0] ... intarray [n/2]
   var rArray as array = intarray [n/2+1] ... intarray [n]

   lArray = mergesort(lArray )
   rArray = mergesort(rArray )

   return merge(lArray, rArray )
end procedure

procedure merge( var l_array as array, var r_array as array )

   var result as array
   while (l_array and r_array have elements )
      if (l_array [0] > r_array [0] )
         add r_array [0] to the end of result
         remove r_array [0] from r_array
      else
         add l_array [0] to the end of result
         remove l_array [0] from l_array
      end if
   end while
   
   while (l_array has elements )
      add l_array [0] to the end of result
      remove l_array [0] from l_array
   end while
   
   while (r_array has elements )
      add r_array [0] to the end of result
      remove r_array [0] from r_array
   end while
   
   return result
	
end procedure

In the above pseudo-code, we have two routines i.e. Mergesort and merge. The routine Mergesort splits the input array into an individual array that is easy enough to sort. Then it calls the merge routine.

The merge routine merges the individual sub-arrays and returns a resultant sorted array. Having seen the algorithm and pseudo-code for Merge sort, let's now illustrate this technique using an example.

MergeSort Illustration

Consider the following array that is to be sorted using this technique.

Merge sort illustration

Now according to the Merge sort algorithm, we will split this array at its mid element into two sub-arrays. Then we will continue splitting the sub-arrays into smaller arrays till we get a single element in each array.

Once each sub-array has only one element in it, we merge the elements. While merging, we compare the elements and ensure that they are in order in the merged array. So we work our way up to get a merged array that is sorted.

The process is shown below:

Merge sort process

As shown in the above illustration, we see that the array is divided repeatedly and then merged to get a sorted array. With this concept in mind, let's move onto the implementation of Mergesort in Java programming language.

Merge Sort Implementation In Java

We can implement the technique in Java using two approaches.

Iterative Merge Sort

This is a bottom-up approach. The sub-arrays of one element each are sorted and merged to form two-element arrays. These arrays are then merged to form four-element arrays and so on. This way the sorted array is built by going upwards.

The below Java example shows the iterative Merge Sort technique.

import java.util.Arrays;

class Main
{
	// merge arrays : intArray[start...mid] and intArray[mid+1...end]
	public static void merge(int[] intArray, int[] temp, int start, int mid, int end)
	{
		int k = start, i = start, j = mid + 1;

		// traverse through elements of left and right arrays
		while (i <= mid && j <= end) {
			if (intArray[i] < intArray[j]) {
				temp[k++] = intArray[i++];
			} else {
				temp[k++] = intArray[j++];
			}
		}

		// Copy remaining elements
		while (i <= mid) {
			temp[k++] = intArray[i++];
		}

		// copy temp array back to the original array to reflect sorted order
		for (i = start; i <= end; i++) {
			intArray[i] = temp[i];
		}
	}
// sorting intArray[low...high] using iterative approach
	public static void mergeSort(int[] intArray)
	{
		int low = 0;
		int high = intArray.length - 1;

		// sort array intArray[] using temporary array temp
		int[] temp = Arrays.copyOf(intArray, intArray.length);

		// divide the array into blocks of size m
		// m = [1, 2, 4, 8, 16...]
		for (int m = 1; m <= high - low; m = 2*m)
		{
			for (int i = low; i < high; i += 2*m)
			{
				int start = i;
				int mid = i + m - 1;
				int end = Integer.min(i + 2 * m - 1, high);
                //call merge routine to merge the arrays
				merge(intArray, temp, start, mid, end);
			}
		}
	}

	public static void main(String[] args)
	{
	    //define array to be sorted
		int[] intArray = { 10,23,-11,54,2,9,-10,45 };
        //print the original array
		System.out.println("Original Array : " + Arrays.toString(intArray));
		//call mergeSort routine
		mergeSort(intArray);
		//print the sorted array
		System.out.println("Sorted Array : " + Arrays.toString(intArray));
	}
}

Output:

Original Array : [10, 23, -11, 54, 2, 9, -10, 45]
Sorted Array : [-11, -10, 2, 9, 10, 23, 45, 54]

Iterative Merge Sort - Output

Recursive Merge Sort

This is a top-down approach. In this approach, the array to be sorted is broken down into smaller arrays until each array contains only one element. Then the sorting becomes easy to implement.

The following Java code implements the recursive approach of the Merge sort technique.

import java.util.Arrays; 
public class Main { 
    public static void merge_Sort(int[] numArray) { 
        //return if array is empty
        if(numArray == null) { 
            return; 
        } 
          if(numArray.length > 1) { 
            int mid = numArray.length / 2; //find mid of the array
  
            // left half of the array 
            int[] left = new int[mid]; 
            for(int i = 0; i < mid; i++) { 
                left[i] = numArray[i]; 
            } 
            // right half of the array 
            int[] right = new int[numArray.length - mid]; 
            for(int i = mid; i < numArray.length; i++) { 
                right[i - mid] = numArray[i]; 
            } 
            merge_Sort(left);   //call merge_Sort routine for left half of the array 
            merge_Sort(right);   // call merge_Sort routine for right half of the array
  
            int i = 0; 
            int j = 0; 
            int k = 0; 
              // now merge two arrays
            while(i < left.length && j < right.length) { 
                if(left[i] < right[j]) { 
                    numArray[k] = left[i]; 
                    i++; 
                } 
                else { 
                    numArray[k] = right[j]; 
                    j++; 
                } 
                k++; 
            } 
         
   // remaining elements 
            while(i < left.length) { 
                numArray[k] = left[i]; 
                i++; 
                k++; 
            } 
            while(j < right.length) { 
                numArray[k] = right[j]; 
                j++; 
                k++; 
            } 
        } 
    }
public static void main(String[] args) { 
        int numArray[] = {10, 23, -11, 54, 2, 9, -10, 45}; 
        int i=0; 
        //print original array       
        System.out.println("Original Array:" + Arrays.toString(numArray)); 
        //call merge_Sort routine to sort arrays recursively
        merge_Sort(numArray); 
        //print the sorted array
        System.out.println("Sorted array:" + Arrays.toString(numArray)); 
   } 
} 
  

Output:

Original Array:[10, 23, -11, 54, 2, 9, -10, 45]
Sorted array:[-11, -10, 2, 9, 10, 23, 45, 54]

Recursive MergeSort - Output

In the next section, let's switch from arrays and use the technique to sort the linked list and array list data structures.

Sort Linked List Using Merge Sort In Java

Mergesort technique is the most preferred one for sorting linked lists. Other sorting techniques perform poorly when it comes to the linked list because of its mostly sequential access.

The following program sorts a linked list using this technique.

import java.util.*;
// A singly linked list node
class Node
{
	int data;
	Node next;

	Node(int data, Node next) {
		this.data = data;
		this.next = next;
	}
};

class Main {
    //two sorted linked list are merged together to form one sorted linked list
	public static Node Sorted_MergeSort(Node node1, Node node2) {
		//return other list if one is null
		if (node1 == null)
			return node2;

		else if (node2 == null)
			return node1;

		Node result;

		// Pick either node1 or node2, and recur
		if (node1.data <= node2.data) {
			result = node1;
			result.next = Sorted_MergeSort(node1.next, node2);
		}
		else {
			result = node2;
			result.next = Sorted_MergeSort(node1, node2.next);
		}

		return result;
	}
//splits the given linked list into two halves
	public static Node[] FrontBackSplit(Node source) {
		// empty list
		if (source == null || source.next == null) {
			return new Node[]{ source, null } ;
		}

		Node slow_ptr = source;
		Node fast_ptr = source.next;

		// Advance 'fast' two nodes, and advance 'slow' one node
		while (fast_ptr != null) {
			fast_ptr = fast_ptr.next;
			if (fast_ptr != null) {
				slow_ptr = slow_ptr.next;
				fast_ptr = fast_ptr.next;
			}
		}

		// split the list at slow_ptr just before mid
		Node[] l_list = new Node[]{ source, slow_ptr.next };
		slow_ptr.next = null;

		return l_list;
	}

	// use Merge sort technique to sort the linked list
	public static Node Merge_Sort(Node head) {
		// list is empty or has single node
		if (head == null || head.next == null) {
			return head;
		}

		// Split head into 'left' and 'right' sublists
		Node[] l_list = FrontBackSplit(head);
		Node left = l_list[0];
		Node right = l_list[1];

		// Recursively sort the sublists
		left = Merge_Sort(left);
		right = Merge_Sort(right);

		// merge the sorted sublists
		return Sorted_MergeSort(left, right);
	}
// function to print nodes of given linked list
	public static void printNode(Node head) {
		Node node_ptr = head;
		while (node_ptr != null)  {
			System.out.print(node_ptr.data + " -> ");
			node_ptr = node_ptr.next;
		}

		System.out.println("null");
	}

	public static void main(String[] args) {
		// input linked list
		int[] l_list = { 4,1,6,2,7,3,8 };
        
		Node head = null;
		for (int key: l_list) {
			head = new Node(key, head);
		}
		//print the original list
       		 System.out.println("Original Linked List: ");
        		printNode(head);
		// sort the list
		head = Merge_Sort(head);

		// print the sorted list
		System.out.println("\nSorted Linked List:");
		printNode(head);
	}
}

Output:

Original Linked List:
8 -> 3 -> 7 -> 2 -> 6 -> 1 -> 4 -> null
Sorted Linked List:
1 -> 2 -> 3 -> 4 -> 6 -> 7 -> 8 -> null

Output - Sort Linked list

Sort ArrayList Using Merge Sort In Java

Like Arrays and Linked lists, we can also use this technique for sorting an ArrayList. We will use similar routines to divide the ArrayList recursively and then merge the sublists.

The below Java code implements the Merge sort technique for ArrayList.

import java.util.ArrayList;

class Main {
//splits arrayList into sub lists.
public static void merge_Sort(ArrayList<Integer> numList){
  int mid;
  ArrayList<Integer> left = new ArrayList<>();
  ArrayList<Integer> right = new ArrayList<>();
  
  if (numList.size() > 1) {
     mid = numList.size() / 2;
        // left sublist
        for (int i = 0; i < mid; i++) 
            left.add(numList.get(i));
 
        //right sublist
        for (int j = mid; j < numList.size(); j++)
            right.add(numList.get(j));
     //recursively call merge_Sort for left and right sublists        
     merge_Sort(left);
     merge_Sort(right);
     //now merge both arrays 
     merge(numList, left, right);
  }
}
private static void merge(ArrayList<Integer> numList, ArrayList<Integer> left, ArrayList<Integer> right){
  //temporary arraylist to build the merged list
  ArrayList<Integer> temp = new ArrayList<>(); 
  
  //initial indices for lists 
  int numbersIndex = 0;    
  int leftIndex = 0;
  int rightIndex = 0;
  //traverse left and righ lists for merging
  while (leftIndex < left.size() && rightIndex < right.size()) {
    if (left.get(leftIndex) < right.get(rightIndex) ) {
            numList.set(numbersIndex, left.get(leftIndex));
            leftIndex++;
        } else {
            numList.set(numbersIndex, right.get(rightIndex));
            rightIndex++;
        }
        numbersIndex++;
    }
    //copy remaining elements from both lists, if any.
    int tempIndex = 0;
    if (leftIndex >= left.size()) {
        temp = right;
        tempIndex = rightIndex;
    } 
    else {
        temp = left;
        tempIndex = leftIndex;
    }
 
    for (int i = tempIndex; i < temp.size(); i++) {
        numList.set(numbersIndex, temp.get(i));
        numbersIndex++;
    }
 }
public static void main(String[] args) {
    //declare an ArrayList
    ArrayList<Integer> numList = new ArrayList<>();
    int temp;
    //populate the ArrayList with random numbers
    for (int i = 1; i <= 9; i++)
      numList.add( (int)(Math.random() * 50 + 1) );
    //print original ArrayList of random numbers    
    System.out.println("Original ArrayList:");
    for(int val: numList)
      System.out.print(val + " ");
    //call merge_Sort routine 
    merge_Sort(numList);

    //print the sorted ArrayList
    System.out.println("\nSorted ArrayList:");
    for(int ele: numList)
      System.out.print(ele + " ");
    System.out.println();
  }
}

Output:

Original ArrayList:
17 40 36 7 6 23 35 2 38
Sorted ArrayList:
2 6 7 17 23 35 36 38 40

Output - Sort ArrayList

Frequently Asked Questions

Q #1) Can Merge sort be done without Recursion?

Answer: Yes. We can perform a non-recursive Merge sort called ‘iterative Merge sort’. This is a bottom-up approach that begins by merging sub-arrays with a single element into a sub-array of two elements.

Then these 2-element sub-arrays are merged into 4-element sub arrays and so on using iterative constructs. This process continues until we have a sorted array.

Q #2) Can Merge sort be done in place?

Answer: Merge sort generally is not in-place. But we can make it in-place by using some clever implementation. For example, by storing two elements value at one position. This can be extracted afterward using modulus and division.

Q #3) What is a 3 way Merge sort?

Answer: The technique we have seen above is a 2-way Merge sort wherein we split the array to be sorted into two parts. Then we sort and merge the array.

In a 3-way Merge sort, instead of splitting the array into 2 parts, we split it into 3 parts, then sort and finally merge it.

Q #4) What is the time complexity of Mergesort?

Answer: The overall time complexity of Merge sort in all cases is O (nlogn).

Q #5) Where is the Merge sort used?

Answer: It is mostly used in sorting the linked list in O (nlogn) time. It is also used in distributed scenarios wherein new data comes in the system before or post sorting. This is also used in various database scenarios.

Conclusion

Merge sort is a stable sort and is performed by first splitting the data set repeatedly into subsets and then sorting and merging these subsets to form a sorted data set. The data set is split until each data set is trivial and easy to sort.

We have seen the recursive and iterative approaches to the sorting technique. We have also discussed the sorting of Linked List and ArrayList data structure using Mergesort.

We will continue with the discussion of more sorting techniques in our upcoming tutorials. Stay Tuned!

=> Visit Here For The Exclusive Java Training Tutorial Series.