1

Below is the code I have written to read the 100000 integers from a text file and to sort them using merge sort.

Issues:

  1. The sorted integers are getting displayed in correct order only in the eclipse console, but when I try to write them to an output text file the order is getting changed.

  2. The inversion count value of 100000 integers from the given text file should be around 2407905288 as per my knowledge but I am getting a value of 8096.

Kindly do help me fix these two issues. thank you so much in advance.

package com.inversioncount;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class inversioncount {

    public static int mergeSort(Integer[] arr, int array_size) {
        int temp[] = new int[array_size];
        return _mergeSort(arr, temp, 0, array_size - 1);
    }

    /* An auxiliary recursive method that sorts the input array and
      returns the number of inversions in the array. */
    public static int _mergeSort(Integer arr[], int[] temp, int left, int right) {
        int mid, count = 0;
        if (right > left) {
            /* Divide the array into two parts and call _mergeSortAndCountInv()
               for each of the parts */
            mid = (right + left) / 2;

            /* Inversion count will be sum of inversions in left-part, right-part
               and number of inversions in merging */
            count  = _mergeSort(arr, temp, left, mid);
            count += _mergeSort(arr, temp, mid + 1, right);

            /* Merge the two parts */
            count += merge(arr, temp, left, mid + 1, right);
        }
        return count;
    }

    /* This method merges two sorted arrays and returns inversion count in
       the arrays.*/
    static int merge(Integer arr[], int temp[], int left, int mid, int right) {
        int x, y, z;
        int count = 0;

        x = left; /* i is index for left subarray*/
        y = mid;  /* j is index for right subarray*/
        z = left; /* k is index for resultant merged subarray*/
        while ((x <= mid - 1) && (y <= right)) {
            if (arr[x] <= arr[y]) {
                temp[z++] = arr[x++];
            } else {
                temp[z++] = arr[y++];
                count = count + (mid - x);
            }
        }

        /* Copy the remaining elements of left subarray
           (if there are any) to temp*/
        while (x <= mid - 1)
            temp[z++] = arr[x++];

        /* Copy the remaining elements of right subarray
           (if there are any) to temp*/
        while (y <= right)
            temp[z++] = arr[y++];

        /* Copy back the merged elements to original array*/
        for (x = left; x <= right; x++)
            arr[x] = temp[x];

        return count;
    }

    // Driver method to test the above function
    public static void main(String[] args) throws FileNotFoundException {
        try {
            BufferedReader br = new BufferedReader(new FileReader("IntegerArray.txt"));
            List<Integer> lines = new ArrayList<Integer>();
            String line;
            while ((line = br.readLine()) != null) {
                lines.add(Integer.parseInt(line));
            }
            br.close();
            Integer[] inputArray = lines.toArray(new Integer[lines.size()]);
            inversioncount.mergeSort(inputArray, inputArray.length - 1);
            System.out.println("Number of inversions are " + mergeSort(inputArray, inputArray.length));
            //BufferedWriter writer = null;
            //writer = new BufferedWriter(new FileWriter("OutputLatest.txt"));
            for (Integer i : inputArray) {
                System.out.println(i);

                // Writing sorted lines into output file
                //writer.write(i);
                //writer.newLine();
            }
        } catch (IOException ie) {
            System.out.print(ie.getMessage());
        }
    }
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Ram
  • 31
  • 3
  • 3
    How to solve your problem: 1) create a test array of 5 elements and compute the inversion count by hand. 2) Do the merge sort *by hand on paper* to see where you need to add things to compute the proper value. 3) Change your code to reflect the procedure you developed by hand, 4) Fire up your debugger and single-step through the code to see if it works as expected. That's how you learn these things. – Jim Mischel Apr 29 '18 at 22:25
  • @JimMischel move fast, break things, learn things the hard way (which is also the only way) :) – JSCoder says Reinstate Monica Apr 30 '18 at 22:30
  • @Ram Hopefully you will be able to find such mistakes using a debugger next time. Learn debugging, it will be good for you. – Sumeet Jun 03 '18 at 06:42
  • @Ram: you can accept one of the answers by clicking on the grey checkmark below its score. – chqrlie Jun 24 '19 at 05:14

4 Answers4

0

Your recursive calls are from left to mid and mid+1 to right as seen here:

count  = _mergeSort(arr, temp, left, mid);
count += _mergeSort(arr, temp, mid+1, right);

Therefore the correct merge function call should be:

count += merge(arr, temp, left, mid, right);

There are also some mistakes in merge definition. Let me point them out to you:

x should vary from left to mid. y should vary from mid+1 to right

  x = left; /* i is index for left subarray*/
  y = mid+1;  /* j is index for right subarray*/
  z = left; /* k is index for resultant merged subarray*/
  while ((x <= mid) && (y <= right))

Also the inversion count is actually count = count + (mid - x) + 1;. You can figure that out by taking a small array of 5 elements.

Also the indices for temp always start from 0.

Therefore the correct merge function is:

static int merge(Integer arr[], int temp[], int left, int mid, int right)
{
  int x, y, z ;
  int count = 0;

  x = left; /* i is index for left subarray*/
  y = mid+1;  /* j is index for right subarray*/
  z = 0; /* k is index for resultant merged subarray*/
  while ((x <= mid) && (y <= right))
  {
    if (arr[x] <= arr[y])
    {
      temp[z++] = arr[x++];
    }
    else
    {
      temp[z++] = arr[y++];

      count = count + (mid - x) + 1;
    }
  }

  /* Copy the remaining elements of left subarray
   (if there are any) to temp*/
  while (x <= mid)
    temp[z++] = arr[x++];

  /* Copy the remaining elements of right subarray
   (if there are any) to temp*/
  while (y <= right)
    temp[z++] = arr[y++];

  /*Copy back the merged elements to original array*/

  z = 0;

  for (x=left; x <= right; x++)
    arr[x] = temp[z++];

  return count;
}
Sumeet
  • 8,086
  • 3
  • 25
  • 45
0

This is task from Hackerrank/Practice/Tutorials/Cracking the Coding Interview/Merge Sort: Counting Inversions:

static long mergeSort(int[] arr, int l, int r) {
    long swaps = 0;

    if (l < r) {
        int p = (l + r) / 2;
        swaps += mergeSort(arr, l, p);
        swaps += mergeSort(arr, p + 1, r);

        // Merge
        int[] la = Arrays.copyOfRange(arr, l, p + 1);
        int[] ra = Arrays.copyOfRange(arr, p + 1, r + 1);

        int i = l, lai = 0, rai = 0;
        while (lai < la.length && rai < ra.length) {
            if (ra[rai] < la[lai]) {
                arr[i++] = ra[rai++];
                swaps += la.length - lai;
            } else {
                arr[i++] = la[lai++];
            }
        }
        while (lai < la.length) {
            arr[i++] = la[lai++];
        }
        while (rai < ra.length) {
            arr[i++] = ra[rai++];
        }
    }
    return swaps;
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
0

Use long instead of int for inv_count. Also, change the return type from int to long.

As with the above solution, int is overflowing.

double-beep
  • 5,031
  • 17
  • 33
  • 41
0

There are multiple issues in your code:

  • you use type int to compute the number of inversions. The maximum value for type int is 2147483647. You should instead use type long which can handle values up to 9223372036854775807.
  • you call mergeSort twice in the main() method, with conflicting array sizes:

        inversioncount.mergeSort(inputArray, inputArray.length - 1);
        System.out.println("Number of inversions are " + mergeSort(inputArray, inputArray.length));
    

    You should instead call it just once with the correct length:

        long inversion_count = mergeSort(inputArray, inputArray.length);
        System.out.println("Number of inversions is " + inversion_count + "\n");
    
  • It is confusing to specify right as the index of the last element in the slice. A much more regular and idiomatic approach uses right as the index of the first element past the end of the slice.

Here is a corrected version:

package com.inversioncount;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class inversioncount {

    public static long mergeSort(Integer[] arr, int array_size) {
        int temp[] = new int[array_size];
        return _mergeSort(arr, temp, 0, array_size);
    }

    /* An auxiliary recursive method that sorts a slice of the input array and
      returns the number of inversions. */
    static long _mergeSort(Integer arr[], int[] temp, int left, int right) {
        long count = 0;
        if (right - left > 1) {
            /* Divide the array into two parts and call _mergeSort() for each of the parts */
            int mid = (right + left + 1) / 2;

            /* Inversion count will be sum of inversions in left-part, right-part
               and number of inversions in merging */
            count += _mergeSort(arr, temp, left, mid);
            count += _mergeSort(arr, temp, mid, right);

            /* Merge the two parts */
            count += merge(arr, temp, left, mid, right);
        }
        return count;
    }

    /* This method merges two sorted slices of the array and returns the inversion count */
    static long merge(Integer arr[], int temp[], int left, int mid, int right) {
        long count = 0;

        int x = left; /* x is index for left subarray */
        int y = mid;  /* y is index for right subarray */
        int z = left; /* z is index for resultant merged subarray */
        while (x < mid && y < right) {
            if (arr[x] <= arr[y]) {
                temp[z++] = arr[x++];
            } else {
                temp[z++] = arr[y++];
                count += mid - x;
            }
        }

        /* Copy the remaining elements of left subarray if any */
        while (x < mid)
            temp[z++] = arr[x++];

        /* Copy the remaining elements of right subarray if any */
        while (y < right)
            temp[z++] = arr[y++];

        /* Copy back the merged elements to original array */
        for (x = left; x < right; x++)
            arr[x] = temp[x];

        return count;
    }

    // Driver method to test the above function
    public static void main(String[] args) throws FileNotFoundException {
        try {
            BufferedReader br = new BufferedReader(new FileReader("IntegerArray.txt"));
            List<Integer> lines = new ArrayList<Integer>();
            String line;
            while ((line = br.readLine()) != null) {
                lines.add(Integer.parseInt(line));
            }
            br.close();

            Integer[] inputArray = lines.toArray(new Integer[lines.size()]);
            long inversion_count = mergeSort(inputArray, inputArray.length);
            System.out.println("Number of inversions is " + inversion_count + "\n");

            //BufferedWriter writer = null;
            //writer = new BufferedWriter(new FileWriter("OutputLatest.txt"));
            for (Integer i : inputArray) {
                System.out.println(i);

                // Writing sorted lines into output file
                //writer.write(i);
                //writer.newLine();
            }
        } catch (IOException ie) {
            System.out.print(ie.getMessage());
        }
    }
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189