diff --git a/DIRECTORY.md b/DIRECTORY.md index 6cecfef02de5..921ddd4f2524 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -496,6 +496,7 @@ * [CocktailShakerSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CocktailShakerSort.java) * [CombSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CombSort.java) * [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CountingSort.java) + * [CountingSortUsingStream](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CountingSortUsingStream.java) * [CycleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CycleSort.java) * [DNFSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DNFSort.java) * [DualPivotQuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java) @@ -512,6 +513,8 @@ * [OddEvenSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/OddEvenSort.java) * [PancakeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PancakeSort.java) * [PigeonholeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PigeonholeSort.java) + * [PseudoCountingSortUsingTreeMap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMap.java) + * [PseudoCountingSortUsingTreeMapAndStream](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStream.java) * [QuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/QuickSort.java) * [RadixSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/RadixSort.java) * [SelectionSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SelectionSort.java) @@ -864,6 +867,7 @@ * [CircleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CircleSortTest.java) * [CocktailShakerSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CocktailShakerSortTest.java) * [CombSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CombSortTest.java) + * [CountingSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CountingSortTest.java) * [DualPivotQuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java) * [DutchNationalFlagSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java) * [ExchangeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java) @@ -875,6 +879,8 @@ * [MergeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/MergeSortTest.java) * [OddEvenSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/OddEvenSortTest.java) * [PancakeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/PancakeSortTest.java) + * [PseudoCountingSortUsingTreeMapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/sorts/PseudoCountingSortUsingTreeMapTest.java) + * [PseudoCountingSortUsingTreeMapAndStreamTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStreamTest.java) * [QuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/QuickSortTest.java) * [SelectionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SelectionSortTest.java) * [SelectionSortRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SelectionSortRecursiveTest.java) diff --git a/src/main/java/com/thealgorithms/sorts/CountingSort.java b/src/main/java/com/thealgorithms/sorts/CountingSort.java index e83271d9ee67..038872045861 100644 --- a/src/main/java/com/thealgorithms/sorts/CountingSort.java +++ b/src/main/java/com/thealgorithms/sorts/CountingSort.java @@ -1,93 +1,54 @@ package com.thealgorithms.sorts; -import static com.thealgorithms.sorts.SortUtils.print; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toMap; - -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.stream.IntStream; -import java.util.stream.Stream; /** - * @author Youssef Ali (https://github.com/youssefAli11997) - * @author Podshivalov Nikita (https://github.com/nikitap492) + * A standard implementation of the Counting Sort algorithm for integer arrays. + * This implementation has a time complexity of O(n + k), where n is the number + * of elements in the input array and k is the range of the input. + * It works only with integer arrays. + * + * The space complexity is O(k), where k is the range of the input integers. + * + * Note: This implementation does not handle negative integers as it + * calculates the range based on the minimum and maximum values of the array. + * */ -class CountingSort implements SortAlgorithm { - - @Override - public > T[] sort(T[] unsorted) { - return sort(Arrays.asList(unsorted)).toArray(unsorted); +public final class CountingSort { + private CountingSort() { } /** - * This method implements the Generic Counting Sort + * Sorts an array of integers using the Counting Sort algorithm. * - * @param list The list to be sorted - *

- * Sorts the list in increasing order The method uses list elements as keys - * in the frequency map + * @param array the array to be sorted + * @return the sorted array */ - @Override - public > List sort(List list) { - Map frequency = new TreeMap<>(); - // The final output array - List sortedArray = new ArrayList<>(list.size()); - - // Counting the frequency of @param array elements - list.forEach(v -> frequency.put(v, frequency.getOrDefault(v, 0) + 1)); - - // Filling the sortedArray - for (Map.Entry element : frequency.entrySet()) { - for (int j = 0; j < element.getValue(); j++) { - sortedArray.add(element.getKey()); - } + public static int[] sort(int[] array) { + if (array.length == 0) { + return array; } - return sortedArray; - } - - /** - * Stream Counting Sort The same as method {@link CountingSort#sort(List)} } - * but this method uses stream API - * - * @param list The list to be sorted - */ - private static > List streamSort(List list) { - return list.stream().collect(toMap(k -> k, v -> 1, (v1, v2) -> v1 + v2, TreeMap::new)).entrySet().stream().flatMap(entry -> IntStream.rangeClosed(1, entry.getValue()).mapToObj(t -> entry.getKey())).collect(toList()); - } - - // Driver Program - public static void main(String[] args) { - // Integer Input - List unsortedInts = Stream.of(4, 23, 6, 78, 1, 54, 23, 1, 9, 231, 9, 12).collect(toList()); - CountingSort countingSort = new CountingSort(); - - System.out.println("Before Sorting:"); - print(unsortedInts); + int max = Arrays.stream(array).max().orElse(Integer.MIN_VALUE); + int min = Arrays.stream(array).min().orElse(Integer.MAX_VALUE); + int range = max - min + 1; - // Output => 1 1 4 6 9 9 12 23 23 54 78 231 - System.out.println("After Sorting:"); - print(countingSort.sort(unsortedInts)); - System.out.println("After Sorting By Streams:"); - print(streamSort(unsortedInts)); + int[] count = new int[range]; + int[] output = new int[array.length]; - System.out.println("\n------------------------------\n"); - - // String Input - List unsortedStrings = Stream.of("c", "a", "e", "b", "d", "a", "f", "g", "c").collect(toList()); + for (int value : array) { + count[value - min]++; + } - System.out.println("Before Sorting:"); - print(unsortedStrings); + for (int i = 1; i < count.length; i++) { + count[i] += count[i - 1]; + } - // Output => a a b c c d e f g - System.out.println("After Sorting:"); - print(countingSort.sort(unsortedStrings)); + for (int i = array.length - 1; i >= 0; i--) { + output[count[array[i] - min] - 1] = array[i]; + count[array[i] - min]--; + } - System.out.println("After Sorting By Streams:"); - print(streamSort(unsortedStrings)); + return output; } } diff --git a/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMap.java b/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMap.java new file mode 100644 index 000000000000..f92f2b71b674 --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMap.java @@ -0,0 +1,51 @@ +package com.thealgorithms.sorts; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * CountingSort is a generic implementation of the counting sort algorithm. + * This implementation sorts elements that implement the Comparable interface. + * + * @author Youssef Ali (https://github.com/youssefAli11997) + * @author Podshivalov Nikita (https://github.com/nikitap492) + */ +class PseudoCountingSortUsingTreeMap implements SortAlgorithm { + @Override + public > T[] sort(T[] array) { + return sort(Arrays.asList(array)).toArray(array); + } + + /** + * Sorts the provided list using the counting sort algorithm. + * + * @param list The list to be sorted. + * @param The type of elements in the list, must be Comparable. + * @return A sorted list in increasing order. + */ + @Override + public > List sort(List list) { + return extractSortedArray(computeFequencyMap(list)); + } + + private static > List extractSortedArray(final Map frequencyMap) { + List sortedList = new ArrayList<>(); + for (final Map.Entry entry : frequencyMap.entrySet()) { + for (int i = 0; i < entry.getValue(); i++) { + sortedList.add(entry.getKey()); + } + } + return sortedList; + } + + private static > Map computeFequencyMap(final List list) { + Map frequencyMap = new TreeMap<>(); + for (final T element : list) { + frequencyMap.put(element, frequencyMap.getOrDefault(element, 0) + 1); + } + return frequencyMap; + } +} diff --git a/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStream.java b/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStream.java new file mode 100644 index 000000000000..ad75c3ba11f1 --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStream.java @@ -0,0 +1,27 @@ +package com.thealgorithms.sorts; + +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; + +import java.util.Arrays; +import java.util.List; +import java.util.TreeMap; +import java.util.stream.IntStream; + +public class PseudoCountingSortUsingTreeMapAndStream implements SortAlgorithm { + @Override + public > T[] sort(T[] array) { + return streamSort(Arrays.asList(array)).toArray(array); + } + + /** + * Sorts the provided list using the counting sort algorithm with the Stream API. + * + * @param list The list to be sorted. + * @param The type of elements in the list, must be Comparable. + * @return A sorted list in increasing order. + */ + private static > List streamSort(List list) { + return list.stream().collect(toMap(k -> k, v -> 1, Integer::sum, TreeMap::new)).entrySet().stream().flatMap(entry -> IntStream.rangeClosed(1, entry.getValue()).mapToObj(t -> entry.getKey())).collect(toList()); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/CountingSortTest.java b/src/test/java/com/thealgorithms/sorts/CountingSortTest.java new file mode 100644 index 000000000000..ce6b6aef63c0 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/CountingSortTest.java @@ -0,0 +1,27 @@ +package com.thealgorithms.sorts; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +public class CountingSortTest { + + record TestCase(int[] inputArray, int[] expectedArray) { + } + + static Stream provideTestCases() { + return Stream.of(new TestCase(new int[] {}, new int[] {}), new TestCase(new int[] {4}, new int[] {4}), new TestCase(new int[] {6, 1, 99, 27, 15, 23, 36}, new int[] {1, 6, 15, 23, 27, 36, 99}), new TestCase(new int[] {6, 1, 27, 15, 23, 27, 36, 23}, new int[] {1, 6, 15, 23, 23, 27, 27, 36}), + new TestCase(new int[] {5, 5, 5, 5, 5}, new int[] {5, 5, 5, 5, 5}), 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}, new int[] {-9, -1, 1, 3, 4, 5}), + new TestCase(new int[] {0, 0, 0, 0}, new int[] {0, 0, 0, 0}), new TestCase(new int[] {3, 3, -1, -1, 2, 2, 0, 0}, new int[] {-1, -1, 0, 0, 2, 2, 3, 3}), new TestCase(new int[] {-3, -2, -1, -5, -4}, new int[] {-5, -4, -3, -2, -1}), + new TestCase(new int[] {1000, 500, 100, 50, 10, 5, 1}, new int[] {1, 5, 10, 50, 100, 500, 1000})); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + public void testCountingSort(TestCase testCase) { + int[] outputArray = CountingSort.sort(testCase.inputArray); + assertArrayEquals(testCase.expectedArray, outputArray); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStreamTest.java b/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStreamTest.java new file mode 100644 index 000000000000..f6112263e2b9 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapAndStreamTest.java @@ -0,0 +1,8 @@ +package com.thealgorithms.sorts; + +public class PseudoCountingSortUsingTreeMapAndStreamTest extends SortingAlgorithmTest { + @Override + SortAlgorithm getSortAlgorithm() { + return new PseudoCountingSortUsingTreeMapAndStream(); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapTest.java b/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapTest.java new file mode 100644 index 000000000000..04695c21d474 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/PseudoCountingSortUsingTreeMapTest.java @@ -0,0 +1,8 @@ +package com.thealgorithms.sorts; + +public class PseudoCountingSortUsingTreeMapTest extends SortingAlgorithmTest { + @Override + SortAlgorithm getSortAlgorithm() { + return new PseudoCountingSortUsingTreeMap(); + } +}