mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-05 16:27:33 +08:00
Add CountingInversions
algorithm (#5745)
This commit is contained in:
@ -251,6 +251,7 @@
|
|||||||
* divideandconquer
|
* divideandconquer
|
||||||
* [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
|
* [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
|
||||||
* [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
|
* [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
|
||||||
|
* [CountingInversions](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/CountingInversions.java)
|
||||||
* [MedianOfTwoSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java)
|
* [MedianOfTwoSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java)
|
||||||
* [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
|
* [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
|
||||||
* [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
|
* [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
|
||||||
@ -833,6 +834,7 @@
|
|||||||
* divideandconquer
|
* divideandconquer
|
||||||
* [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java)
|
* [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java)
|
||||||
* [ClosestPairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java)
|
* [ClosestPairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java)
|
||||||
|
* [CountingInversionsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java)
|
||||||
* [MedianOfTwoSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java)
|
* [MedianOfTwoSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java)
|
||||||
* [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java)
|
* [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java)
|
||||||
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
|
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
package com.thealgorithms.divideandconquer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for counting the number of inversions in an array.
|
||||||
|
* <p>
|
||||||
|
* An inversion is a pair (i, j) such that i < j and arr[i] > arr[j].
|
||||||
|
* This class implements a divide-and-conquer approach, similar to merge sort,
|
||||||
|
* to count the number of inversions efficiently.
|
||||||
|
* <p>
|
||||||
|
* Time Complexity: O(n log n)
|
||||||
|
* Space Complexity: O(n) (due to temporary arrays during merge step)
|
||||||
|
*
|
||||||
|
* <p>Applications:
|
||||||
|
* - Used in algorithms related to sorting and permutation analysis.
|
||||||
|
* - Helps in determining how far an array is from being sorted.
|
||||||
|
* - Applicable in bioinformatics and signal processing.
|
||||||
|
*
|
||||||
|
* <p>This class cannot be instantiated, as it is intended to provide
|
||||||
|
* only static utility methods.
|
||||||
|
*
|
||||||
|
* @author Hardvan
|
||||||
|
*/
|
||||||
|
public final class CountingInversions {
|
||||||
|
private CountingInversions() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the number of inversions in the given array.
|
||||||
|
*
|
||||||
|
* @param arr The input array of integers.
|
||||||
|
* @return The total number of inversions in the array.
|
||||||
|
*/
|
||||||
|
public static int countInversions(int[] arr) {
|
||||||
|
return mergeSortAndCount(arr, 0, arr.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively divides the array into two halves, sorts them, and counts
|
||||||
|
* the number of inversions. Uses a modified merge sort approach.
|
||||||
|
*
|
||||||
|
* @param arr The input array.
|
||||||
|
* @param left The starting index of the current segment.
|
||||||
|
* @param right The ending index of the current segment.
|
||||||
|
* @return The number of inversions within the segment [left, right].
|
||||||
|
*/
|
||||||
|
private static int mergeSortAndCount(int[] arr, int left, int right) {
|
||||||
|
if (left >= right) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mid = left + (right - left) / 2;
|
||||||
|
int inversions = 0;
|
||||||
|
|
||||||
|
inversions += mergeSortAndCount(arr, left, mid);
|
||||||
|
inversions += mergeSortAndCount(arr, mid + 1, right);
|
||||||
|
inversions += mergeAndCount(arr, left, mid, right);
|
||||||
|
return inversions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges two sorted subarrays and counts the cross-inversions between them.
|
||||||
|
* A cross-inversion occurs when an element from the right subarray is
|
||||||
|
* smaller than an element from the left subarray.
|
||||||
|
*
|
||||||
|
* @param arr The input array.
|
||||||
|
* @param left The starting index of the first subarray.
|
||||||
|
* @param mid The ending index of the first subarray and midpoint of the segment.
|
||||||
|
* @param right The ending index of the second subarray.
|
||||||
|
* @return The number of cross-inversions between the two subarrays.
|
||||||
|
*/
|
||||||
|
private static int mergeAndCount(int[] arr, int left, int mid, int right) {
|
||||||
|
int[] leftArr = new int[mid - left + 1];
|
||||||
|
int[] rightArr = new int[right - mid];
|
||||||
|
|
||||||
|
System.arraycopy(arr, left, leftArr, 0, mid - left + 1);
|
||||||
|
System.arraycopy(arr, mid + 1, rightArr, 0, right - mid);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
int k = left;
|
||||||
|
int inversions = 0;
|
||||||
|
|
||||||
|
while (i < leftArr.length && j < rightArr.length) {
|
||||||
|
if (leftArr[i] <= rightArr[j]) {
|
||||||
|
arr[k++] = leftArr[i++];
|
||||||
|
} else {
|
||||||
|
arr[k++] = rightArr[j++];
|
||||||
|
inversions += mid + 1 - left - i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < leftArr.length) {
|
||||||
|
arr[k++] = leftArr[i++];
|
||||||
|
}
|
||||||
|
while (j < rightArr.length) {
|
||||||
|
arr[k++] = rightArr[j++];
|
||||||
|
}
|
||||||
|
|
||||||
|
return inversions;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.thealgorithms.divideandconquer;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class CountingInversionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCountInversions() {
|
||||||
|
int[] arr = {2, 3, 8, 6, 1};
|
||||||
|
assertEquals(5, CountingInversions.countInversions(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoInversions() {
|
||||||
|
int[] arr = {1, 2, 3, 4, 5};
|
||||||
|
assertEquals(0, CountingInversions.countInversions(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleElement() {
|
||||||
|
int[] arr = {1};
|
||||||
|
assertEquals(0, CountingInversions.countInversions(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllInversions() {
|
||||||
|
int[] arr = {5, 4, 3, 2, 1};
|
||||||
|
assertEquals(10, CountingInversions.countInversions(arr));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user