Skip to content

Commit 995b3ef

Browse files
committed
feat: Add CountingInversions new algorithm with Junit tests
1 parent 4a03f42 commit 995b3ef

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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+
public final class CountingInversions {
22+
private CountingInversions() {
23+
}
24+
25+
/**
26+
* Counts the number of inversions in the given array.
27+
*
28+
* @param arr The input array of integers.
29+
* @return The total number of inversions in the array.
30+
*/
31+
public static int countInversions(int[] arr) {
32+
return mergeSortAndCount(arr, 0, arr.length - 1);
33+
}
34+
35+
/**
36+
* Recursively divides the array into two halves, sorts them, and counts
37+
* the number of inversions. Uses a modified merge sort approach.
38+
*
39+
* @param arr The input array.
40+
* @param left The starting index of the current segment.
41+
* @param right The ending index of the current segment.
42+
* @return The number of inversions within the segment [left, right].
43+
*/
44+
private static int mergeSortAndCount(int[] arr, int left, int right) {
45+
if (left >= right) {
46+
return 0;
47+
}
48+
49+
int mid = left + (right - left) / 2;
50+
int inversions = 0;
51+
52+
inversions += mergeSortAndCount(arr, left, mid);
53+
inversions += mergeSortAndCount(arr, mid + 1, right);
54+
inversions += mergeAndCount(arr, left, mid, right);
55+
return inversions;
56+
}
57+
58+
/**
59+
* Merges two sorted subarrays and counts the cross-inversions between them.
60+
* A cross-inversion occurs when an element from the right subarray is
61+
* smaller than an element from the left subarray.
62+
*
63+
* @param arr The input array.
64+
* @param left The starting index of the first subarray.
65+
* @param mid The ending index of the first subarray and midpoint of the segment.
66+
* @param right The ending index of the second subarray.
67+
* @return The number of cross-inversions between the two subarrays.
68+
*/
69+
private static int mergeAndCount(int[] arr, int left, int mid, int right) {
70+
int[] leftArr = new int[mid - left + 1];
71+
int[] rightArr = new int[right - mid];
72+
73+
System.arraycopy(arr, left, leftArr, 0, mid - left + 1);
74+
System.arraycopy(arr, mid + 1, rightArr, 0, right - mid);
75+
76+
int i = 0, j = 0, k = left, inversions = 0;
77+
78+
while (i < leftArr.length && j < rightArr.length) {
79+
if (leftArr[i] <= rightArr[j]) {
80+
arr[k++] = leftArr[i++];
81+
} else {
82+
arr[k++] = rightArr[j++];
83+
inversions += (mid + 1) - (left + i);
84+
}
85+
}
86+
87+
while (i < leftArr.length) {
88+
arr[k++] = leftArr[i++];
89+
}
90+
while (j < rightArr.length) {
91+
arr[k++] = rightArr[j++];
92+
}
93+
94+
return inversions;
95+
}
96+
}
Lines changed: 32 additions & 0 deletions
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)