package edu.princeton.cs.excercise.ch2;
import edu.princeton.cs.introcs.StdIn;
import edu.princeton.cs.introcs.StdOut;
/*************************************************************************
* Compilation: javac Inversions.java
* Execution: java Inversions < input.txt
*
* Read in N integers and count number of inversions in N log N time.
*
*************************************************************************/
public class Inversions {
// merge and count
private static long merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
long inversions = 0;
// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}
// merge back to a[]
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (less(aux[j], aux[i])) { a[k] = aux[j++]; inversions += (mid - i + 1); }
else a[k] = aux[i++];
}
return inversions;
}
// return the number of inversions in the subarray b[lo..hi]
// side effect b[lo..hi] is rearranged in ascending order
private static long count(Comparable[] a, Comparable[] b, Comparable[] aux, int lo, int hi) {
long inversions = 0;
if (hi <= lo) return 0;
int mid = lo + (hi - lo) / 2;
inversions += count(a, b, aux, lo, mid);
inversions += count(a, b, aux, mid+1, hi);
inversions += merge(b, aux, lo, mid, hi);
assert inversions == brute(a, lo, hi);
return inversions;
}
// count number of inversions in the array a[] - do not overwrite a[]
public static long count(Comparable[] a) {
Comparable[] b = new Comparable[a.length];
Comparable[] aux = new Comparable[a.length];
for (int i = 0; i < a.length; i++) b[i] = a[i];
long inversions = count(a, b, aux, 0, a.length - 1);
return inversions;
}
// is v < w ?
private static boolean less(Comparable v, Comparable w) {
return (v.compareTo(w) < 0);
}
// count number of inversions in a[lo..hi] via brute force (for debugging only)
private static long brute(Comparable[] a, int lo, int hi) {
long inversions = 0;
for (int i = lo; i <= hi; i++)
for (int j = i + 1; j <= hi; j++)
if (less(a[j], a[i])) inversions++;
return inversions;
}
// count number of inversions via brute force
public static long brute(Comparable[] a) {
return brute(a, 0, a.length - 1);
}
// generate N real numbers between 0 and 1, and mergesort them
public static void main(String[] args) {
int[] a = StdIn.readInts();
int N = a.length;
Integer[] b = new Integer[N];
for (int i = 0; i < N; i++)
b[i] = a[i];
StdOut.println(Inversions.count(b));
StdOut.println(Inversions.brute(b));
}
}