From 8ef69bc85404a714c186f8aead26cd3d92595610 Mon Sep 17 00:00:00 2001 From: Alex Klymenko Date: Fri, 21 Jun 2024 22:37:58 +0300 Subject: [PATCH] Improving BitonicSort (#5244) * Improving BitonicSort * Moving max method to SortingUtils * Adding Javadoc to merge method * Fix for test and code improvements * Improving code readability * Renaming method parameters --------- Co-authored-by: alx Co-authored-by: vil02 <65706193+vil02@users.noreply.github.com> --- .../com/thealgorithms/sorts/BitonicSort.java | 149 +++++++++++------- .../thealgorithms/sorts/BitonicSortTest.java | 8 + 2 files changed, 99 insertions(+), 58 deletions(-) create mode 100644 src/test/java/com/thealgorithms/sorts/BitonicSortTest.java diff --git a/src/main/java/com/thealgorithms/sorts/BitonicSort.java b/src/main/java/com/thealgorithms/sorts/BitonicSort.java index b4b26299562f..90d204818729 100644 --- a/src/main/java/com/thealgorithms/sorts/BitonicSort.java +++ b/src/main/java/com/thealgorithms/sorts/BitonicSort.java @@ -1,79 +1,112 @@ package com.thealgorithms.sorts; -/* Java program for Bitonic Sort. Note that this program -works only when size of input is a power of 2. */ -public class BitonicSort { - - /* The parameter dir indicates the sorting direction, - ASCENDING or DESCENDING; if (a[i] > a[j]) agrees - with the direction, then a[i] and a[j] are - interchanged. */ - void compAndSwap(int[] a, int i, int j, int dir) { - if ((a[i] > a[j] && dir == 1) || (a[i] < a[j] && dir == 0)) { - // Swapping elements - int temp = a[i]; - a[i] = a[j]; - a[j] = temp; - } +import java.util.Arrays; +import java.util.function.BiPredicate; + +/** + * BitonicSort class implements the SortAlgorithm interface using the bitonic sort technique. + */ +public class BitonicSort implements SortAlgorithm { + private enum Direction { + DESCENDING, + ASCENDING, } - /* It recursively sorts a bitonic sequence in ascending - order, if dir = 1, and in descending order otherwise - (means dir=0). The sequence to be sorted starts at - index position low, the parameter cnt is the number - of elements to be sorted.*/ - void bitonicMerge(int[] a, int low, int cnt, int dir) { - if (cnt > 1) { - int k = cnt / 2; - for (int i = low; i < low + k; i++) { - compAndSwap(a, i, i + k, dir); - } - bitonicMerge(a, low, k, dir); - bitonicMerge(a, low + k, k, dir); + /** + * Sorts the given array using the Bitonic Sort algorithm. + * + * @param the type of elements in the array, which must implement the Comparable interface + * @param array the array to be sorted + * @return the sorted array + */ + @Override + public > T[] sort(T[] array) { + if (array.length == 0) { + return array; } + + final int paddedSize = nextPowerOfTwo(array.length); + T[] paddedArray = Arrays.copyOf(array, paddedSize); + + // Fill the padded part with a maximum value + final T maxValue = max(array); + Arrays.fill(paddedArray, array.length, paddedSize, maxValue); + + bitonicSort(paddedArray, 0, paddedSize, Direction.ASCENDING); + return Arrays.copyOf(paddedArray, array.length); } - /* This funcion first produces a bitonic sequence by - recursively sorting its two halves in opposite sorting - orders, and then calls bitonicMerge to make them in - the same order */ - void bitonicSort(int[] a, int low, int cnt, int dir) { + private > void bitonicSort(final T[] array, final int low, final int cnt, final Direction direction) { if (cnt > 1) { - int k = cnt / 2; + final int k = cnt / 2; - // sort in ascending order since dir here is 1 - bitonicSort(a, low, k, 1); + // Sort first half in ascending order + bitonicSort(array, low, k, Direction.ASCENDING); - // sort in descending order since dir here is 0 - bitonicSort(a, low + k, k, 0); + // Sort second half in descending order + bitonicSort(array, low + k, cnt - k, Direction.DESCENDING); - // Will merge whole sequence in ascending order - // since dir=1. - bitonicMerge(a, low, cnt, dir); + // Merge the whole sequence in ascending order + bitonicMerge(array, low, cnt, direction); } } - /*Caller of bitonicSort for sorting the entire array - of length N in ASCENDING order */ - void sort(int[] a, int n, int up) { - bitonicSort(a, 0, n, up); + /** + * Merges the bitonic sequence in the specified direction. + * + * @param the type of elements in the array, which must be Comparable + * @param array the array containing the bitonic sequence to be merged + * @param low the starting index of the sequence to be merged + * @param cnt the number of elements in the sequence to be merged + * @param direction the direction of sorting + */ + private > void bitonicMerge(T[] array, int low, int cnt, Direction direction) { + if (cnt > 1) { + final int k = cnt / 2; + + final BiPredicate areSorted = (direction == Direction.ASCENDING) ? (a, b) -> a.compareTo(b) < 0 : (a, b) -> a.compareTo(b) > 0; + for (int i = low; i < low + k; i++) { + if (!areSorted.test(array[i], array[i + k])) { + SortUtils.swap(array, i, i + k); + } + } + + bitonicMerge(array, low, k, direction); + bitonicMerge(array, low + k, cnt - k, direction); + } } - /* A utility function to print array of size n */ - static void printArray(int[] arr) { - int n = arr.length; - for (int i = 0; i < n; ++i) { - System.out.print(arr[i] + " "); + /** + * Finds the next power of two greater than or equal to the given number. + * + * @param n the number + * @return the next power of two + */ + private static int nextPowerOfTwo(int n) { + int count = 0; + + // First n in the below condition is for the case where n is 0 + if ((n & (n - 1)) == 0) { + return n; + } + + while (n != 0) { + n >>= 1; + count += 1; } - System.out.println(); + + return 1 << count; } - public static void main(String[] args) { - int[] a = {3, 7, 4, 8, 6, 2, 1, 5}; - int up = 1; - BitonicSort ob = new BitonicSort(); - ob.sort(a, a.length, up); - System.out.println("\nSorted array"); - printArray(a); + /** + * Finds the maximum element in the given array. + * + * @param the type of elements in the array, which must implement the Comparable interface + * @param array the array to be searched + * @return the maximum element in the array + * @throws IllegalArgumentException if the array is null or empty + */ + private static > T max(final T[] array) { + return Arrays.stream(array).max(Comparable::compareTo).orElseThrow(); } } diff --git a/src/test/java/com/thealgorithms/sorts/BitonicSortTest.java b/src/test/java/com/thealgorithms/sorts/BitonicSortTest.java new file mode 100644 index 000000000000..60c4bbe9d342 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/BitonicSortTest.java @@ -0,0 +1,8 @@ +package com.thealgorithms.sorts; + +public class BitonicSortTest extends SortingAlgorithmTest { + @Override + SortAlgorithm getSortAlgorithm() { + return new BitonicSort(); + } +}