Mergesort in java

Mergesort is a divide and conquer algorithm. It works by breaking an array into sub-arrays and then recursively sorting the sub-arrays.

Steps for Mergesort

  1. Divide the list with n elements into n sublists with each sublist having 1 element. We will divide list into 2 sublists by dividing in the middle and then recursively dividing the 2 sublists from the middle until we are left with sublists with all of them having 1 element.
  2. Merge all the sublists to produce sorted sublists and then merge the already merged sublists. Do that until only one list is created and no more merging can be performed.

Mergesort example

Here is an animation of the mergesort

Mergesort Animation
Mergesort Animation

Mergesort Java implementation

Here is a java implementation. I have added a lot of logging so that from the output all the steps become clear.
package com.programtalk.mergesort.example;

import java.util.Arrays;

public class MergerSort {
	
	
	public static void main(String[] args) {
		int[] array4Sort = { 8,5,6,7,2,1,3,4};
		System.out.println("To be sorted array: " + Arrays.toString(array4Sort));
		sort(array4Sort);
		System.out.println("Sorted array: " +  Arrays.toString(array4Sort));
	}

	
	
	public static void sort(int[] array4Sort) {
		int[] emptyArray = new int[array4Sort.length];
		int rightEndIndex = array4Sort.length - 1;
		int leftStartIndex = 0;
		recusrsiveMergeSort(array4Sort, emptyArray, leftStartIndex, rightEndIndex);
	}

	private static void recusrsiveMergeSort(int[] array4Sort, int[] tmpArray, int leftIndex, int rightIndex) {
		if (rightIndex <= leftIndex) {
			return;
		}

		int center = (rightIndex + leftIndex) / 2;
		recusrsiveMergeSort(array4Sort, tmpArray, leftIndex, center);
		recusrsiveMergeSort(array4Sort, tmpArray, center + 1, rightIndex);
		mergeLeftAndRight(array4Sort, tmpArray, leftIndex, center + 1, rightIndex);
	}

	private static void mergeLeftAndRight(int[] array2Merge, int[] tmpArrayUsed4Merge, int leftStartIndex, int rightStartIndex,
			int rightEndIndex) {

		System.out.println(
				"left array: " + Arrays.toString(Arrays.copyOfRange(array2Merge, leftStartIndex, rightStartIndex)));
		System.out.println(
				"right array: " + Arrays.toString(Arrays.copyOfRange(array2Merge, rightStartIndex, rightEndIndex + 1)));
		
		int leftEndIndex = rightStartIndex - 1;
		int tmpArray4MergeIndex = leftStartIndex;
		final int startIndexForMergedArray = leftStartIndex;

		for (;leftStartIndex <= leftEndIndex && rightStartIndex <= rightEndIndex; tmpArray4MergeIndex++) {
			// the lower value element goes to the merged array
			if (array2Merge[leftStartIndex] < (array2Merge[rightStartIndex]))
				tmpArrayUsed4Merge[tmpArray4MergeIndex] = array2Merge[leftStartIndex++];
			else
				tmpArrayUsed4Merge[tmpArray4MergeIndex] = array2Merge[rightStartIndex++];
		}
		
		while (leftStartIndex <= leftEndIndex) {
			tmpArrayUsed4Merge[tmpArray4MergeIndex++] = array2Merge[leftStartIndex++];
		}
		while (rightStartIndex <= rightEndIndex) {
			tmpArrayUsed4Merge[tmpArray4MergeIndex++] = array2Merge[rightStartIndex++];
		}

		System.out.println("Temporary array after merging:" + Arrays.toString(tmpArrayUsed4Merge));
		int length = rightEndIndex - startIndexForMergedArray +1;
		System.arraycopy(tmpArrayUsed4Merge, startIndexForMergedArray, array2Merge, startIndexForMergedArray, length);

	}

}

Output:

To be sorted array: [8, 5, 6, 7, 2, 1, 3, 4]
left array: [8]
right array: [5]
Temporary array after merging:[5, 8, 0, 0, 0, 0, 0, 0]
left array: [6]
right array: [7]
Temporary array after merging:[5, 8, 6, 7, 0, 0, 0, 0]
left array: [5, 8]
right array: [6, 7]
Temporary array after merging:[5, 6, 7, 8, 0, 0, 0, 0]
left array: [2]
right array: [1]
Temporary array after merging:[5, 6, 7, 8, 1, 2, 0, 0]
left array: [3]
right array: [4]
Temporary array after merging:[5, 6, 7, 8, 1, 2, 3, 4]
left array: [1, 2]
right array: [3, 4]
Temporary array after merging:[5, 6, 7, 8, 1, 2, 3, 4]
left array: [5, 6, 7, 8]
right array: [1, 2, 3, 4]
Temporary array after merging:[1, 2, 3, 4, 5, 6, 7, 8]
Sorted array: [1, 2, 3, 4, 5, 6, 7, 8]

10 thoughts on “Mergesort in java”

  1. hi, i dont get how does mergeleftandright gets recursively called. stuck on mergesort since a week! could you possibly explain it

    Reply
    • mergeleftandright does not do recursion over itself. I have added some more outputs in the below program. And have reduced the array size also so as to get a better understanding. Try it out


      package com.programtalk.mergesort.example;

      import java.util.Arrays;

      public class MergerSort {

      public static void main(String[] args) {
      int[] array4Sort = { 8,5,6,7};
      System.out.println("To be sorted array: " + Arrays.toString(array4Sort));
      sort(array4Sort);
      System.out.println("Sorted array: " + Arrays.toString(array4Sort));
      }

      public static void sort(int[] array4Sort) {
      int[] emptyArray = new int[array4Sort.length];
      int rightEndIndex = array4Sort.length - 1;
      int leftStartIndex = 0;
      recusrsiveMergeSort(array4Sort, emptyArray, leftStartIndex, rightEndIndex);
      }

      private static void recusrsiveMergeSort(int[] array4Sort, int[] tmpArray, int leftIndex, int rightIndex) {
      if (rightIndex <= leftIndex) {
      return;
      }

      int center = (rightIndex + leftIndex) / 2;
      System.out.println("recusrsiveMergeSort for left array, right index:" + center + ", left index:" + leftIndex);
      recusrsiveMergeSort(array4Sort, tmpArray, leftIndex, center);
      System.out.println("recusrsiveMergeSort for right array, right index:" + rightIndex+ ", left index:" + (center + 1));
      recusrsiveMergeSort(array4Sort, tmpArray, center + 1, rightIndex);
      mergeLeftAndRight(array4Sort, tmpArray, leftIndex, center + 1, rightIndex);
      }

      private static void mergeLeftAndRight(int[] array2Merge, int[] tmpArrayUsed4Merge, int leftStartIndex, int rightStartIndex,
      int rightEndIndex) {
      System.out.println("inside : mergeLeftAndRight");
      System.out.println(
      "left array: " + Arrays.toString(Arrays.copyOfRange(array2Merge, leftStartIndex, rightStartIndex)));
      System.out.println(
      "right array: " + Arrays.toString(Arrays.copyOfRange(array2Merge, rightStartIndex, rightEndIndex + 1)));

      int leftEndIndex = rightStartIndex - 1;
      int tmpArray4MergeIndex = leftStartIndex;
      final int startIndexForMergedArray = leftStartIndex;

      for (;leftStartIndex <= leftEndIndex && rightStartIndex <= rightEndIndex; tmpArray4MergeIndex++) {
      // the lower value element goes to the merged array
      if (array2Merge[leftStartIndex] < (array2Merge[rightStartIndex]))
      tmpArrayUsed4Merge[tmpArray4MergeIndex] = array2Merge[leftStartIndex++];
      else
      tmpArrayUsed4Merge[tmpArray4MergeIndex] = array2Merge[rightStartIndex++];
      }

      while (leftStartIndex <= leftEndIndex) {
      tmpArrayUsed4Merge[tmpArray4MergeIndex++] = array2Merge[leftStartIndex++];
      }
      while (rightStartIndex <= rightEndIndex) {
      tmpArrayUsed4Merge[tmpArray4MergeIndex++] = array2Merge[rightStartIndex++];
      }

      System.out.println("Temporary array after merging:" + Arrays.toString(tmpArrayUsed4Merge));
      int length = rightEndIndex - startIndexForMergedArray +1;
      System.arraycopy(tmpArrayUsed4Merge, startIndexForMergedArray, array2Merge, startIndexForMergedArray, length);

      }

      }

      Reply
      • thank you for your time and effort, but i still dont get how the recusrsiveMergeSort gets called after the first call to mergeLeftAndRight

        Reply
        • You can only understand it by following the flow of the program, that is why i tried to reduce the number of elements in the array. First the left array is sorted recursively and then the right array is sorted recursively. When you reduce the array to be sorted to {8,5} then the output is as below
          To be sorted array: [8, 5]
          recusrsiveMergeSort for left array, right index:0, left index:0
          recusrsiveMergeSort for right array, right index:1, left index:1
          inside : mergeLeftAndRight
          left array: [8]
          right array: [5]
          Temporary array after merging:[5, 8]
          Sorted array: [5, 8]

          Let me try to explain the flow:
          1. recusrsiveMergeSort is called from sort for array {5,8}
          2. recusrsiveMergeSort is called within recusrsiveMergeSort for left array which is 5.
          3. Inside recusrsiveMergeSort both right index and left index are 0 and hence confirming to the exit condition of recursion. So the method stops recursion for this call and returns.
          By exit condition i mean this code:
          if (rightIndex <= leftIndex) {
          return;
          }

          4. recusrsiveMergeSort is called within recusrsiveMergeSort for right array which is 8.
          5. Inside recusrsiveMergeSort both right index and left index are 1 and hence confirming to the exit condition of recursion. So the method stops recursion for this call and returns.
          6. Now mergeLeftAndRight is called.

          Reply
          • yes i get it sir, but if we are working with a bigger array say with 8 elements… and all the above steps have been done, i.e. mergeleftandright is called. how does the flow go back to recusrsiveMergeSort after the mergeleftandright is exited.

          • Here is the output for a bigger array
            To be sorted array: [8, 5, 6, 7, 2, 1, 3, 4]
            recusrsiveMergeSort for left array, right index:3, left index:0
            recusrsiveMergeSort for left array, right index:1, left index:0
            recusrsiveMergeSort for left array, right index:0, left index:0
            recusrsiveMergeSort for right array, right index:1, left index:1
            inside : mergeLeftAndRight
            left array: [8]
            right array: [5]
            Temporary array after merging:[5, 8, 0, 0, 0, 0, 0, 0]
            recusrsiveMergeSort for right array, right index:3, left index:2
            recusrsiveMergeSort for left array, right index:2, left index:2
            recusrsiveMergeSort for right array, right index:3, left index:3
            inside : mergeLeftAndRight
            left array: [6]
            right array: [7]
            Temporary array after merging:[5, 8, 6, 7, 0, 0, 0, 0]
            inside : mergeLeftAndRight
            left array: [5, 8]
            right array: [6, 7]
            Temporary array after merging:[5, 6, 7, 8, 0, 0, 0, 0]
            recusrsiveMergeSort for right array, right index:7, left index:4
            recusrsiveMergeSort for left array, right index:5, left index:4
            recusrsiveMergeSort for left array, right index:4, left index:4
            recusrsiveMergeSort for right array, right index:5, left index:5
            inside : mergeLeftAndRight
            left array: [2]
            right array: [1]
            Temporary array after merging:[5, 6, 7, 8, 1, 2, 0, 0]
            recusrsiveMergeSort for right array, right index:7, left index:6
            recusrsiveMergeSort for left array, right index:6, left index:6
            recusrsiveMergeSort for right array, right index:7, left index:7
            inside : mergeLeftAndRight
            left array: [3]
            right array: [4]
            Temporary array after merging:[5, 6, 7, 8, 1, 2, 3, 4]
            inside : mergeLeftAndRight
            left array: [1, 2]
            right array: [3, 4]
            Temporary array after merging:[5, 6, 7, 8, 1, 2, 3, 4]
            inside : mergeLeftAndRight
            left array: [5, 6, 7, 8]
            right array: [1, 2, 3, 4]
            Temporary array after merging:[1, 2, 3, 4, 5, 6, 7, 8]
            Sorted array: [1, 2, 3, 4, 5, 6, 7, 8]

            Flow would be something like this

            To be sorted array: [8, 5, 6, 7, 2, 1, 3, 4]
            recusrsiveMergeSort([8, 5, 6, 7, 2, 1, 3, 4])
            recusrsiveMergeSort([8, 5, 6, 7])
            recusrsiveMergeSort([8, 5])
            recusrsiveMergeSort([8])
            recusrsiveMergeSort([5])
            inside : mergeLeftAndRight
            recusrsiveMergeSort([6, 7])
            recusrsiveMergeSort([6])
            recusrsiveMergeSort([7])
            inside : mergeLeftAndRight
            inside : mergeLeftAndRight
            recusrsiveMergeSort([2, 1, 3, 4])
            recusrsiveMergeSort([2, 1])
            recusrsiveMergeSort([2])
            recusrsiveMergeSort([1])
            inside : mergeLeftAndRight
            recusrsiveMergeSort([3, 4])
            recusrsiveMergeSort([3])
            recusrsiveMergeSort([4])
            inside : mergeLeftAndRight
            inside : mergeLeftAndRight
            inside : mergeLeftAndRight
            Sorted array: [1, 2, 3, 4, 5, 6, 7, 8]

            mergeLeftAndRight would not be executed for the lowest level arrays that is arrays with only one element. That you can see from above flow

          • i am sorry i am a slow learner. can you explain how

            recusrsiveMergeSort([6, 7])

            gets executed after inside : mergeLeftAndRight.

          • You need to understand recursion in order to get the flow.

            recusrsiveMergeSort([8, 5, 6, 7])
            recusrsiveMergeSort([8, 5]) –> first call within 8, 5, 6, 7
            recusrsiveMergeSort([8]) — first call within 8,5
            recusrsiveMergeSort([5]) — second call within 8,5
            inside : mergeLeftAndRight — called inside 8,5
            Here the recusrsiveMergeSort([8, 5]) returns and the next line to be executed would be

            recusrsiveMergeSort([6, 7]) –> second call within 8, 5, 6, 7

          • thank you for your patience, i think i have a better understanding now, but i have a question. what do you mean by “recusrsiveMergeSort([8, 5]) returns” . is it like recusrsiveMergeSort([6, 7]) is still waiting in the background to get executed?

          • No, this is next line to be executed.
            Read some recursion tutorials and execute the examples, Only when you have the idea of recursion, you can understand mergesort code

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.