Skip to content

Commit 1e01ec5

Browse files
authored
Add CountingInversions algorithm (#5745)
1 parent 0020ab2 commit 1e01ec5

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

DIRECTORY.md

+2
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
* divideandconquer
252252
* [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
253253
* [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
254+
* [CountingInversions](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/CountingInversions.java)
254255
* [MedianOfTwoSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java)
255256
* [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
256257
* [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
@@ -833,6 +834,7 @@
833834
* divideandconquer
834835
* [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java)
835836
* [ClosestPairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java)
837+
* [CountingInversionsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java)
836838
* [MedianOfTwoSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java)
837839
* [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java)
838840
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.thealgorithms.divideandconquer;
2+
3+
/**
4+
* A utility class for counting the number of inversions in an array.
5+
* <p>
6+
* An inversion is a pair (i, j) such that i < j and arr[i] > arr[j].
7+
* This class implements a divide-and-conquer approach, similar to merge sort,
8+
* to count the number of inversions efficiently.
9+
* <p>
10+
* Time Complexity: O(n log n)
11+
* Space Complexity: O(n) (due to temporary arrays during merge step)
12+
*
13+
* <p>Applications:
14+
* - Used in algorithms related to sorting and permutation analysis.
15+
* - Helps in determining how far an array is from being sorted.
16+
* - Applicable in bioinformatics and signal processing.
17+
*
18+
* <p>This class cannot be instantiated, as it is intended to provide
19+
* only static utility methods.
20+
*
21+
* @author Hardvan
22+
*/
23+
public final class CountingInversions {
24+
private CountingInversions() {
25+
}
26+
27+
/**
28+
* Counts the number of inversions in the given array.
29+
*
30+
* @param arr The input array of integers.
31+
* @return The total number of inversions in the array.
32+
*/
33+
public static int countInversions(int[] arr) {
34+
return mergeSortAndCount(arr, 0, arr.length - 1);
35+
}
36+
37+
/**
38+
* Recursively divides the array into two halves, sorts them, and counts
39+
* the number of inversions. Uses a modified merge sort approach.
40+
*
41+
* @param arr The input array.
42+
* @param left The starting index of the current segment.
43+
* @param right The ending index of the current segment.
44+
* @return The number of inversions within the segment [left, right].
45+
*/
46+
private static int mergeSortAndCount(int[] arr, int left, int right) {
47+
if (left >= right) {
48+
return 0;
49+
}
50+
51+
int mid = left + (right - left) / 2;
52+
int inversions = 0;
53+
54+
inversions += mergeSortAndCount(arr, left, mid);
55+
inversions += mergeSortAndCount(arr, mid + 1, right);
56+
inversions += mergeAndCount(arr, left, mid, right);
57+
return inversions;
58+
}
59+
60+
/**
61+
* Merges two sorted subarrays and counts the cross-inversions between them.
62+
* A cross-inversion occurs when an element from the right subarray is
63+
* smaller than an element from the left subarray.
64+
*
65+
* @param arr The input array.
66+
* @param left The starting index of the first subarray.
67+
* @param mid The ending index of the first subarray and midpoint of the segment.
68+
* @param right The ending index of the second subarray.
69+
* @return The number of cross-inversions between the two subarrays.
70+
*/
71+
private static int mergeAndCount(int[] arr, int left, int mid, int right) {
72+
int[] leftArr = new int[mid - left + 1];
73+
int[] rightArr = new int[right - mid];
74+
75+
System.arraycopy(arr, left, leftArr, 0, mid - left + 1);
76+
System.arraycopy(arr, mid + 1, rightArr, 0, right - mid);
77+
78+
int i = 0;
79+
int j = 0;
80+
int k = left;
81+
int inversions = 0;
82+
83+
while (i < leftArr.length && j < rightArr.length) {
84+
if (leftArr[i] <= rightArr[j]) {
85+
arr[k++] = leftArr[i++];
86+
} else {
87+
arr[k++] = rightArr[j++];
88+
inversions += mid + 1 - left - i;
89+
}
90+
}
91+
92+
while (i < leftArr.length) {
93+
arr[k++] = leftArr[i++];
94+
}
95+
while (j < rightArr.length) {
96+
arr[k++] = rightArr[j++];
97+
}
98+
99+
return inversions;
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.thealgorithms.divideandconquer;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
public class CountingInversionsTest {
8+
9+
@Test
10+
public void testCountInversions() {
11+
int[] arr = {2, 3, 8, 6, 1};
12+
assertEquals(5, CountingInversions.countInversions(arr));
13+
}
14+
15+
@Test
16+
public void testNoInversions() {
17+
int[] arr = {1, 2, 3, 4, 5};
18+
assertEquals(0, CountingInversions.countInversions(arr));
19+
}
20+
21+
@Test
22+
public void testSingleElement() {
23+
int[] arr = {1};
24+
assertEquals(0, CountingInversions.countInversions(arr));
25+
}
26+
27+
@Test
28+
public void testAllInversions() {
29+
int[] arr = {5, 4, 3, 2, 1};
30+
assertEquals(10, CountingInversions.countInversions(arr));
31+
}
32+
}

0 commit comments

Comments
 (0)