Count Inversions in an array

Inversion Count for an array indicates – how far (or close) the array is from being sorted. If array is already sorted then inversion count is 0. If array is sorted in reverse order that inversion count is the maximum.
Formally speaking, two elements a[i] and a[j] form an inversion if a[i] > a[j] and i < j

METHOD 2(Enhance Merge Sort)
Suppose we know the number of inversions in the left half and right half of the array (let be inv1 and inv2), what kinds of inversions are not accounted for in Inv1 + Inv2? The answer is – the inversions we have to count during the merge step. Therefore, to get number of inversions, we need to add number of inversions in left subarray, right subarray and merge().

How to get number of inversions in merge()?
In merge process, let i is used for indexing left sub-array and j for right sub-array. At any step in merge(), if a[i] is greater than a[j], then there are (mid – i) inversions. because left and right subarrays are sorted, so all the remaining elements in left-subarray (a[i+1], a[i+2] … a[mid]) will be greater than a[j]

Note that above code modifies (or sorts) the input array. If we want to count only inversions then we need to create a copy of original array and call mergeSort() on copy.
Time Complexity: O(nlogn)Algorithmic Paradigm: Divide and Conquer

I think there exists a simpler solution
sort the array
e.g. 4,5,6,1,2,3 becomes 1,2,3,4,5,6
find the displacement for a given element e.g. 4 which was initially at 0 is now at index 3. Thus displacement is 3.

Total number of inversions should be sum of all the displacement towards right.
Only 4,5,6 are displaced right, total = 3+3+3 = 9

Not sure if any of the above methods have similar implementation but here is my approach. Basically I am using I ,j where I holds the iterator for every element in the array and J just iterates all elements before it.

As we are using unsigned for counter which is generally what size_type returns the following replacements need to be done.

k -= jump;
if (k < 0) k += count;

should be

k += jump;
if (k >= count) k -= count;

rotate (term + left, range + movecount, movecount);

should be

rotate (term + left, range + movecount, range);

Arun

You need to change

inv_count += mid – i to
inv_count += (mid-left+1-i);

else, the result coming is not correct.

Thanks,

GeeksforGeeks

@Arun: Please take a closer look at the code. The value of mid is (left + right)/2. Let us know if you find any case for which the given code doesn’t produce the correct result.

bartender

We are passing mid+1 into merge routine,so everything works out.Read my other comment for additional details.

Ankit Malhotra

Simplified the code to a single merge sort function which returns the inversions. This implementation is in place and reduces looping when consecutive elements on the right side need me be moved for a single element on the left.

If I understand the logic correctly, we are constructing BST from the array elements and maintaining a count on each node. The idea here is every parent node must maintain the number of nodes that branched on to it’s right side (right count). The above code fails if there are equal element which cause the count to be incremented. Equal nodes won’t participate in inversions. The count (rc) will be used to track the number of inversions.

However, when the array is reverse sorted, the tree will be fully right skewed. While inserting i-th node, we need to visit previous (i-1) nodes, so the worst case complexity is no better than O(n^2).

Where as merge sort procedure doesn’t depend on data to be sorted. What ever may be the permutation of input data, merge sort will sort the array in O(NlogN) time, so the inversion count.

Let me know if I am missing something to understand.

Decoder

What if we insert equal element to right child of equal element, In this case count won’t be incremented.