Skip to content

refactor: BFPRT #5445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 77 additions & 45 deletions src/main/java/com/thealgorithms/others/BFPRT.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
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 {
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) {
if (k < 1 || k > arr.length) {
return null;
}
int minKth = getMinKthByBFPRT(arr, k);
int[] res = new int[k];
int index = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] < minKth) {
res[index++] = arr[i];
for (int value : arr) {
if (value < minKth) {
res[index++] = value;
}
}
for (; index != res.length; index++) {
Expand All @@ -27,17 +35,39 @@ public static int[] getMinKNumsByBFPRT(int[] arr, int k) {
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) {
int[] copyArr = copyArray(arr);
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) {
int[] copyArr = new int[arr.length];
System.arraycopy(arr, 0, copyArr, 0, arr.length);
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) {
if (begin == end) {
return arr[begin];
Expand All @@ -54,12 +84,12 @@ public static int bfprt(int[] arr, int begin, int end, int i) {
}

/**
* wikipedia: https://en.wikipedia.org/wiki/Median_of_medians .
* Finds the median of medians as the pivot element.
*
* @param arr an array.
* @param begin begin num.
* @param end end num.
* @return median of medians.
* @param arr the input array
* @param begin the starting index
* @param end the ending index
* @return the median of medians
*/
public static int medianOfMedians(int[] arr, int begin, int end) {
int num = end - begin + 1;
Expand All @@ -71,12 +101,15 @@ public static int medianOfMedians(int[] arr, int begin, int end) {
return bfprt(mArr, 0, mArr.length - 1, mArr.length / 2);
}

public static void swap(int[] arr, int i, int j) {
int swap = arr[i];
arr[i] = arr[j];
arr[j] = swap;
}

/**
* Partitions the array around a pivot.
*
* @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) {
int small = begin - 1;
int cur = begin;
Expand All @@ -90,19 +123,31 @@ public static int[] partition(int[] arr, int begin, int end, int num) {
cur++;
}
}
int[] pivotRange = new int[2];
pivotRange[0] = small + 1;
pivotRange[1] = big - 1;
return pivotRange;
return new int[] {small + 1, big - 1};
}

/**
* 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) {
insertionSort(arr, begin, end);
int sum = begin + end;
int mid = sum / 2 + (sum % 2);
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) {
if (arr == null || arr.length < 2) {
return;
Expand All @@ -118,29 +163,16 @@ public static void insertionSort(int[] arr, int begin, int end) {
}
}

public static void main(String[] args) {
int[] arr = {
11,
9,
1,
3,
9,
2,
2,
5,
6,
5,
3,
5,
9,
7,
2,
5,
5,
1,
9,
};
int[] minK = getMinKNumsByBFPRT(arr, 5);
System.out.println(Arrays.toString(minK));
/**
* Swaps two elements in an array.
*
* @param arr the input array
* @param i the index of the first element
* @param j the index of the second element
*/
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
34 changes: 34 additions & 0 deletions src/test/java/com/thealgorithms/others/BFPRTTest.java
Original file line number Diff line number Diff line change
@@ -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));
}
}