
public class Mergesort {


    /*
    * Perform merge on given array that is partitioned into two sorted parts (following
    * the pseudocode given by Introduction to Algorithms 3rd).
    */
    private static void merge(int[] a, int p, int q, int r) {
        // Calculate size of l and r arrays.
        int n1 = q - p + 1;
        int n2 = r - q;

        // Create l and r arrays.
        int[] left = new int[n1+1];
        int[] right = new int[n2+1];
        for (int i = 0; i < n1; i++)
            left[i] = a[p+i];
        for (int j = 0; j < n2; j++)
            right[j] = a[q+j+1];
        left[n1] = Integer.MAX_VALUE;
        right[n2] = Integer.MAX_VALUE;

        // Perform merge.
        int i = 0;
        int j = 0;
        for (int k = p; k <= r; k++) {
            if (left[i] <= right[j]) {
                a[k] = left[i];
                i++;
            } else {
                a[k] = right[j];
                j++;
            }
        }
    }

    /*
    * Perform mergesort on the given array in the closed interval [p; r]. (following
    * the pseudocode given by Introduction to Algorithms 3rd).
    */
    private static void mergesort(int[] v, int p, int r) {
        if (p < r) {
            int q = (p+r)/2;
            mergesort(v, p, q);
            mergesort(v, q+1, r);
            merge(v, p, q, r);
        }
    }

    /*
    * Sorts the given array using mergesort.
    * Postcondition: The given array is sorted in non-decreasing order.
    */
    public static void sort(int[] v) {
        mergesort(v, 0, v.length-1);
    }

}
