|
1 | 1 | package com.thealgorithms.sorts;
|
2 | 2 |
|
3 |
| -/* Java program for Bitonic Sort. Note that this program |
4 |
| -works only when size of input is a power of 2. */ |
5 |
| -public class BitonicSort { |
6 |
| - |
7 |
| - /* The parameter dir indicates the sorting direction, |
8 |
| - ASCENDING or DESCENDING; if (a[i] > a[j]) agrees |
9 |
| - with the direction, then a[i] and a[j] are |
10 |
| - interchanged. */ |
11 |
| - void compAndSwap(int[] a, int i, int j, int dir) { |
12 |
| - if ((a[i] > a[j] && dir == 1) || (a[i] < a[j] && dir == 0)) { |
13 |
| - // Swapping elements |
14 |
| - int temp = a[i]; |
15 |
| - a[i] = a[j]; |
16 |
| - a[j] = temp; |
17 |
| - } |
| 3 | +import java.util.Arrays; |
| 4 | +import java.util.function.BiPredicate; |
| 5 | + |
| 6 | +/** |
| 7 | + * BitonicSort class implements the SortAlgorithm interface using the bitonic sort technique. |
| 8 | + */ |
| 9 | +public class BitonicSort implements SortAlgorithm { |
| 10 | + private enum Direction { |
| 11 | + DESCENDING, |
| 12 | + ASCENDING, |
18 | 13 | }
|
19 | 14 |
|
20 |
| - /* It recursively sorts a bitonic sequence in ascending |
21 |
| - order, if dir = 1, and in descending order otherwise |
22 |
| - (means dir=0). The sequence to be sorted starts at |
23 |
| - index position low, the parameter cnt is the number |
24 |
| - of elements to be sorted.*/ |
25 |
| - void bitonicMerge(int[] a, int low, int cnt, int dir) { |
26 |
| - if (cnt > 1) { |
27 |
| - int k = cnt / 2; |
28 |
| - for (int i = low; i < low + k; i++) { |
29 |
| - compAndSwap(a, i, i + k, dir); |
30 |
| - } |
31 |
| - bitonicMerge(a, low, k, dir); |
32 |
| - bitonicMerge(a, low + k, k, dir); |
| 15 | + /** |
| 16 | + * Sorts the given array using the Bitonic Sort algorithm. |
| 17 | + * |
| 18 | + * @param <T> the type of elements in the array, which must implement the Comparable interface |
| 19 | + * @param array the array to be sorted |
| 20 | + * @return the sorted array |
| 21 | + */ |
| 22 | + @Override |
| 23 | + public <T extends Comparable<T>> T[] sort(T[] array) { |
| 24 | + if (array.length == 0) { |
| 25 | + return array; |
33 | 26 | }
|
| 27 | + |
| 28 | + final int paddedSize = nextPowerOfTwo(array.length); |
| 29 | + T[] paddedArray = Arrays.copyOf(array, paddedSize); |
| 30 | + |
| 31 | + // Fill the padded part with a maximum value |
| 32 | + final T maxValue = max(array); |
| 33 | + Arrays.fill(paddedArray, array.length, paddedSize, maxValue); |
| 34 | + |
| 35 | + bitonicSort(paddedArray, 0, paddedSize, Direction.ASCENDING); |
| 36 | + return Arrays.copyOf(paddedArray, array.length); |
34 | 37 | }
|
35 | 38 |
|
36 |
| - /* This funcion first produces a bitonic sequence by |
37 |
| - recursively sorting its two halves in opposite sorting |
38 |
| - orders, and then calls bitonicMerge to make them in |
39 |
| - the same order */ |
40 |
| - void bitonicSort(int[] a, int low, int cnt, int dir) { |
| 39 | + private <T extends Comparable<T>> void bitonicSort(final T[] array, final int low, final int cnt, final Direction direction) { |
41 | 40 | if (cnt > 1) {
|
42 |
| - int k = cnt / 2; |
| 41 | + final int k = cnt / 2; |
43 | 42 |
|
44 |
| - // sort in ascending order since dir here is 1 |
45 |
| - bitonicSort(a, low, k, 1); |
| 43 | + // Sort first half in ascending order |
| 44 | + bitonicSort(array, low, k, Direction.ASCENDING); |
46 | 45 |
|
47 |
| - // sort in descending order since dir here is 0 |
48 |
| - bitonicSort(a, low + k, k, 0); |
| 46 | + // Sort second half in descending order |
| 47 | + bitonicSort(array, low + k, cnt - k, Direction.DESCENDING); |
49 | 48 |
|
50 |
| - // Will merge whole sequence in ascending order |
51 |
| - // since dir=1. |
52 |
| - bitonicMerge(a, low, cnt, dir); |
| 49 | + // Merge the whole sequence in ascending order |
| 50 | + bitonicMerge(array, low, cnt, direction); |
53 | 51 | }
|
54 | 52 | }
|
55 | 53 |
|
56 |
| - /*Caller of bitonicSort for sorting the entire array |
57 |
| - of length N in ASCENDING order */ |
58 |
| - void sort(int[] a, int n, int up) { |
59 |
| - bitonicSort(a, 0, n, up); |
| 54 | + /** |
| 55 | + * Merges the bitonic sequence in the specified direction. |
| 56 | + * |
| 57 | + * @param <T> the type of elements in the array, which must be Comparable |
| 58 | + * @param array the array containing the bitonic sequence to be merged |
| 59 | + * @param low the starting index of the sequence to be merged |
| 60 | + * @param cnt the number of elements in the sequence to be merged |
| 61 | + * @param direction the direction of sorting |
| 62 | + */ |
| 63 | + private <T extends Comparable<T>> void bitonicMerge(T[] array, int low, int cnt, Direction direction) { |
| 64 | + if (cnt > 1) { |
| 65 | + final int k = cnt / 2; |
| 66 | + |
| 67 | + final BiPredicate<T, T> areSorted = (direction == Direction.ASCENDING) ? (a, b) -> a.compareTo(b) < 0 : (a, b) -> a.compareTo(b) > 0; |
| 68 | + for (int i = low; i < low + k; i++) { |
| 69 | + if (!areSorted.test(array[i], array[i + k])) { |
| 70 | + SortUtils.swap(array, i, i + k); |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + bitonicMerge(array, low, k, direction); |
| 75 | + bitonicMerge(array, low + k, cnt - k, direction); |
| 76 | + } |
60 | 77 | }
|
61 | 78 |
|
62 |
| - /* A utility function to print array of size n */ |
63 |
| - static void printArray(int[] arr) { |
64 |
| - int n = arr.length; |
65 |
| - for (int i = 0; i < n; ++i) { |
66 |
| - System.out.print(arr[i] + " "); |
| 79 | + /** |
| 80 | + * Finds the next power of two greater than or equal to the given number. |
| 81 | + * |
| 82 | + * @param n the number |
| 83 | + * @return the next power of two |
| 84 | + */ |
| 85 | + private static int nextPowerOfTwo(int n) { |
| 86 | + int count = 0; |
| 87 | + |
| 88 | + // First n in the below condition is for the case where n is 0 |
| 89 | + if ((n & (n - 1)) == 0) { |
| 90 | + return n; |
| 91 | + } |
| 92 | + |
| 93 | + while (n != 0) { |
| 94 | + n >>= 1; |
| 95 | + count += 1; |
67 | 96 | }
|
68 |
| - System.out.println(); |
| 97 | + |
| 98 | + return 1 << count; |
69 | 99 | }
|
70 | 100 |
|
71 |
| - public static void main(String[] args) { |
72 |
| - int[] a = {3, 7, 4, 8, 6, 2, 1, 5}; |
73 |
| - int up = 1; |
74 |
| - BitonicSort ob = new BitonicSort(); |
75 |
| - ob.sort(a, a.length, up); |
76 |
| - System.out.println("\nSorted array"); |
77 |
| - printArray(a); |
| 101 | + /** |
| 102 | + * Finds the maximum element in the given array. |
| 103 | + * |
| 104 | + * @param <T> the type of elements in the array, which must implement the Comparable interface |
| 105 | + * @param array the array to be searched |
| 106 | + * @return the maximum element in the array |
| 107 | + * @throws IllegalArgumentException if the array is null or empty |
| 108 | + */ |
| 109 | + private static <T extends Comparable<T>> T max(final T[] array) { |
| 110 | + return Arrays.stream(array).max(Comparable::compareTo).orElseThrow(); |
78 | 111 | }
|
79 | 112 | }
|
0 commit comments