refactor: BFPRT (#5445)

refactor: adding javadocs and tests for BFPRT
This commit is contained in:
Alex Klymenko
2024-09-09 09:07:30 +02:00
committed by GitHub
parent fa2231788f
commit bded78f888
2 changed files with 111 additions and 45 deletions

View File

@ -1,14 +1,22 @@
package com.thealgorithms.others; package com.thealgorithms.others;
import java.util.Arrays;
/** /**
* BFPRT algorithm. * The BFPRT (Median of Medians) algorithm implementation.
* It provides a way to find the k-th smallest element in an unsorted array
* with an optimal worst-case time complexity of O(n).
* This algorithm is used to find the k smallest numbers in an array.
*/ */
public final class BFPRT { public final class BFPRT {
private BFPRT() { private BFPRT() {
} }
/**
* Returns the k smallest elements from the array using the BFPRT algorithm.
*
* @param arr the input array
* @param k the number of smallest elements to return
* @return an array containing the k smallest elements, or null if k is invalid
*/
public static int[] getMinKNumsByBFPRT(int[] arr, int k) { public static int[] getMinKNumsByBFPRT(int[] arr, int k) {
if (k < 1 || k > arr.length) { if (k < 1 || k > arr.length) {
return null; return null;
@ -16,9 +24,9 @@ public final class BFPRT {
int minKth = getMinKthByBFPRT(arr, k); int minKth = getMinKthByBFPRT(arr, k);
int[] res = new int[k]; int[] res = new int[k];
int index = 0; int index = 0;
for (int i = 0; i < arr.length; i++) { for (int value : arr) {
if (arr[i] < minKth) { if (value < minKth) {
res[index++] = arr[i]; res[index++] = value;
} }
} }
for (; index != res.length; index++) { for (; index != res.length; index++) {
@ -27,17 +35,39 @@ public final class BFPRT {
return res; return res;
} }
/**
* Returns the k-th smallest element from the array using the BFPRT algorithm.
*
* @param arr the input array
* @param k the rank of the smallest element to find
* @return the k-th smallest element
*/
public static int getMinKthByBFPRT(int[] arr, int k) { public static int getMinKthByBFPRT(int[] arr, int k) {
int[] copyArr = copyArray(arr); int[] copyArr = copyArray(arr);
return bfprt(copyArr, 0, copyArr.length - 1, k - 1); return bfprt(copyArr, 0, copyArr.length - 1, k - 1);
} }
/**
* Creates a copy of the input array.
*
* @param arr the input array
* @return a copy of the array
*/
public static int[] copyArray(int[] arr) { public static int[] copyArray(int[] arr) {
int[] copyArr = new int[arr.length]; int[] copyArr = new int[arr.length];
System.arraycopy(arr, 0, copyArr, 0, arr.length); System.arraycopy(arr, 0, copyArr, 0, arr.length);
return copyArr; return copyArr;
} }
/**
* BFPRT recursive method to find the k-th smallest element.
*
* @param arr the input array
* @param begin the starting index
* @param end the ending index
* @param i the index of the desired smallest element
* @return the k-th smallest element
*/
public static int bfprt(int[] arr, int begin, int end, int i) { public static int bfprt(int[] arr, int begin, int end, int i) {
if (begin == end) { if (begin == end) {
return arr[begin]; return arr[begin];
@ -54,12 +84,12 @@ public final class BFPRT {
} }
/** /**
* wikipedia: https://en.wikipedia.org/wiki/Median_of_medians . * Finds the median of medians as the pivot element.
* *
* @param arr an array. * @param arr the input array
* @param begin begin num. * @param begin the starting index
* @param end end num. * @param end the ending index
* @return median of medians. * @return the median of medians
*/ */
public static int medianOfMedians(int[] arr, int begin, int end) { public static int medianOfMedians(int[] arr, int begin, int end) {
int num = end - begin + 1; int num = end - begin + 1;
@ -71,12 +101,15 @@ public final class BFPRT {
return bfprt(mArr, 0, mArr.length - 1, mArr.length / 2); return bfprt(mArr, 0, mArr.length - 1, mArr.length / 2);
} }
public static void swap(int[] arr, int i, int j) { /**
int swap = arr[i]; * Partitions the array around a pivot.
arr[i] = arr[j]; *
arr[j] = swap; * @param arr the input array
} * @param begin the starting index
* @param end the ending index
* @param num the pivot element
* @return the range where the pivot is located
*/
public static int[] partition(int[] arr, int begin, int end, int num) { public static int[] partition(int[] arr, int begin, int end, int num) {
int small = begin - 1; int small = begin - 1;
int cur = begin; int cur = begin;
@ -90,12 +123,17 @@ public final class BFPRT {
cur++; cur++;
} }
} }
int[] pivotRange = new int[2]; return new int[] {small + 1, big - 1};
pivotRange[0] = small + 1;
pivotRange[1] = big - 1;
return pivotRange;
} }
/**
* Finds the median of the elements between the specified range.
*
* @param arr the input array
* @param begin the starting index
* @param end the ending index
* @return the median of the specified range
*/
public static int getMedian(int[] arr, int begin, int end) { public static int getMedian(int[] arr, int begin, int end) {
insertionSort(arr, begin, end); insertionSort(arr, begin, end);
int sum = begin + end; int sum = begin + end;
@ -103,6 +141,13 @@ public final class BFPRT {
return arr[mid]; return arr[mid];
} }
/**
* Sorts a portion of the array using insertion sort.
*
* @param arr the input array
* @param begin the starting index
* @param end the ending index
*/
public static void insertionSort(int[] arr, int begin, int end) { public static void insertionSort(int[] arr, int begin, int end) {
if (arr == null || arr.length < 2) { if (arr == null || arr.length < 2) {
return; return;
@ -118,29 +163,16 @@ public final class BFPRT {
} }
} }
public static void main(String[] args) { /**
int[] arr = { * Swaps two elements in an array.
11, *
9, * @param arr the input array
1, * @param i the index of the first element
3, * @param j the index of the second element
9, */
2, public static void swap(int[] arr, int i, int j) {
2, int temp = arr[i];
5, arr[i] = arr[j];
6, arr[j] = temp;
5,
3,
5,
9,
7,
2,
5,
5,
1,
9,
};
int[] minK = getMinKNumsByBFPRT(arr, 5);
System.out.println(Arrays.toString(minK));
} }
} }

View File

@ -0,0 +1,34 @@
package com.thealgorithms.others;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class BFPRTTest {
@ParameterizedTest
@MethodSource("minKNumsTestData")
void testGetMinKNumsByBFPRT(int[] arr, int k, int[] expected) {
int[] result = BFPRT.getMinKNumsByBFPRT(arr, k);
assertArrayEquals(expected, result);
}
private static Stream<Arguments> minKNumsTestData() {
return Stream.of(Arguments.of(new int[] {11, 9, 1, 3, 9, 2, 2, 5, 6, 5, 3, 5, 9, 7, 2, 5, 5, 1, 9}, 5, new int[] {1, 1, 2, 2, 2}), Arguments.of(new int[] {3, 2, 1}, 2, new int[] {1, 2}), Arguments.of(new int[] {7, 5, 9, 1, 3, 8, 2, 4, 6}, 3, new int[] {1, 2, 3}));
}
@ParameterizedTest
@MethodSource("minKthTestData")
void testGetMinKthByBFPRT(int[] arr, int k, int expected) {
int result = BFPRT.getMinKthByBFPRT(arr, k);
assertEquals(expected, result);
}
private static Stream<Arguments> minKthTestData() {
return Stream.of(Arguments.of(new int[] {3, 2, 1}, 2, 2), Arguments.of(new int[] {7, 5, 9, 1, 3, 8, 2, 4, 6}, 3, 3), Arguments.of(new int[] {5, 8, 6, 3, 2, 7, 1, 4}, 4, 4));
}
}