refactor: MergeSortNoExtraSpace (#5277)

* refactor: MergeSortNoExtraSpace, change naming, adding test

* checkstyle: fix import ordering, and formatting

* fix: adding negative numbers check, fix possible overflow

* checkstyle: remove newline

---------

Co-authored-by: Alex Klymenko <alx@alx.com>
Co-authored-by: vil02 <65706193+vil02@users.noreply.github.com>
This commit is contained in:
Alex Klymenko 2024-07-09 22:44:42 +02:00 committed by GitHub
parent 14264602de
commit 57f65808ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 87 additions and 38 deletions

View File

@ -1,73 +1,88 @@
package com.thealgorithms.sorts; package com.thealgorithms.sorts;
import java.util.Arrays; import java.util.Arrays;
import java.util.Scanner;
/*This code implements the mergeSort algorithm without extra space /**
For understanding about mergesort visit :https://www.geeksforgeeks.org/merge-sort/ * Implementation of Merge Sort without using extra space for merging.
* This implementation performs in-place merging to sort the array of integers.
*/ */
public final class MergeSortNoExtraSpace { public final class MergeSortNoExtraSpace {
private MergeSortNoExtraSpace() { private MergeSortNoExtraSpace() {
} }
public static void callMergeSort(int[] a, int n) { /**
int maxele = Arrays.stream(a).max().getAsInt() + 1; * Sorts the array using in-place merge sort algorithm.
mergeSort(a, 0, n - 1, maxele); *
* @param array the array to be sorted
* @return the sorted array
* @throws IllegalArgumentException If the array contains negative numbers.
*/
public static int[] sort(int[] array) {
if (array.length == 0) {
return array;
}
if (Arrays.stream(array).anyMatch(s -> s < 0)) {
throw new IllegalArgumentException("Implementation cannot sort negative numbers.");
}
final int maxElement = Arrays.stream(array).max().getAsInt() + 1;
mergeSort(array, 0, array.length - 1, maxElement);
return array;
} }
public static void mergeSort(int[] a, int start, int end, int maxele) { // this function divides the array into 2 halves /**
* Recursively divides the array into two halves, sorts and merges them.
*
* @param array the array to be sorted
* @param start the starting index of the array
* @param end the ending index of the array
* @param maxElement the value greater than any element in the array, used for encoding
*/
public static void mergeSort(int[] array, int start, int end, int maxElement) {
if (start < end) { if (start < end) {
int mid = (start + end) / 2; final int middle = (start + end) >>> 1;
mergeSort(a, start, mid, maxele); mergeSort(array, start, middle, maxElement);
mergeSort(a, mid + 1, end, maxele); mergeSort(array, middle + 1, end, maxElement);
implementMergeSort(a, start, mid, end, maxele); merge(array, start, middle, end, maxElement);
} }
} }
public static void implementMergeSort(int[] a, int start, int mid, int end, /**
int maxele) { // implementation of mergesort * Merges two sorted subarrays [start...middle] and [middle+1...end] in place.
*
* @param array the array containing the subarrays to be merged
* @param start the starting index of the first subarray
* @param middle the ending index of the first subarray and starting index of the second subarray
* @param end the ending index of the second subarray
* @param maxElement the value greater than any element in the array, used for encoding
*/
private static void merge(int[] array, int start, int middle, int end, int maxElement) {
int i = start; int i = start;
int j = mid + 1; int j = middle + 1;
int k = start; int k = start;
while (i <= mid && j <= end) { while (i <= middle && j <= end) {
if (a[i] % maxele <= a[j] % maxele) { if (array[i] % maxElement <= array[j] % maxElement) {
a[k] = a[k] + (a[i] % maxele) * maxele; array[k] = array[k] + (array[i] % maxElement) * maxElement;
k++; k++;
i++; i++;
} else { } else {
a[k] = a[k] + (a[j] % maxele) * maxele; array[k] = array[k] + (array[j] % maxElement) * maxElement;
k++; k++;
j++; j++;
} }
} }
while (i <= mid) { while (i <= middle) {
a[k] = a[k] + (a[i] % maxele) * maxele; array[k] = array[k] + (array[i] % maxElement) * maxElement;
k++; k++;
i++; i++;
} }
while (j <= end) { while (j <= end) {
a[k] = a[k] + (a[j] % maxele) * maxele; array[k] = array[k] + (array[j] % maxElement) * maxElement;
k++; k++;
j++; j++;
} }
for (i = start; i <= end; i++) { for (i = start; i <= end; i++) {
a[i] = a[i] / maxele; array[i] = array[i] / maxElement;
} }
} }
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
System.out.println("Enter array size");
int n = inp.nextInt();
int[] a = new int[n];
System.out.println("Enter array elements");
for (int i = 0; i < n; i++) {
a[i] = inp.nextInt();
}
callMergeSort(a, n);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
inp.close();
}
} }

View File

@ -0,0 +1,34 @@
package com.thealgorithms.sorts;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class MergeSortNoExtraSpaceTest {
record TestCase(int[] inputArray, int[] expectedArray) {
}
static Stream<TestCase> provideTestCases() {
return Stream.of(new TestCase(new int[] {}, new int[] {}), new TestCase(new int[] {1}, new int[] {1}), new TestCase(new int[] {1, 2, 3, 4, 5}, new int[] {1, 2, 3, 4, 5}), new TestCase(new int[] {5, 4, 3, 2, 1}, new int[] {1, 2, 3, 4, 5}),
new TestCase(new int[] {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}, new int[] {1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9}), new TestCase(new int[] {4, 2, 4, 3, 2, 1, 5}, new int[] {1, 2, 2, 3, 4, 4, 5}), new TestCase(new int[] {0, 0, 0, 0}, new int[] {0, 0, 0, 0}),
new TestCase(new int[] {1000, 500, 100, 50, 10, 5, 1}, new int[] {1, 5, 10, 50, 100, 500, 1000}), new TestCase(new int[] {1, 2, 3, 1, 2, 3, 1, 2, 3}, new int[] {1, 1, 1, 2, 2, 2, 3, 3, 3}),
new TestCase(new int[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}), new TestCase(new int[] {2, 1}, new int[] {1, 2}), new TestCase(new int[] {1, 3, 2}, new int[] {1, 2, 3}));
}
@ParameterizedTest
@MethodSource("provideTestCases")
public void testCountingSort(TestCase testCase) {
int[] outputArray = MergeSortNoExtraSpace.sort(testCase.inputArray);
assertArrayEquals(testCase.expectedArray, outputArray);
}
@Test
public void testNegativeNumbers() {
int[] arrayWithNegatives = {1, -2, 3, -4};
assertThrows(IllegalArgumentException.class, () -> MergeSortNoExtraSpace.sort(arrayWithNegatives));
}
}