Skip to content

refactor: cleanup BucketSort #5314

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 5 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
134 changes: 57 additions & 77 deletions src/main/java/com/thealgorithms/sorts/BucketSort.java
Original file line number Diff line number Diff line change
@@ -1,119 +1,99 @@
package com.thealgorithms.sorts;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
* Wikipedia: https://en.wikipedia.org/wiki/Bucket_sort
* BucketSort class provides a static method to sort an array of integers using the Bucket Sort algorithm.
*/
public final class BucketSort {
private BucketSort() {
}

public static void main(String[] args) {
int[] arr = new int[10];

/* generate 10 random numbers from -50 to 49 */
Random random = new Random();
for (int i = 0; i < arr.length; ++i) {
arr[i] = random.nextInt(100) - 50;
}

bucketSort(arr);

/* check array is sorted or not */
for (int i = 0, limit = arr.length - 1; i < limit; ++i) {
assert arr[i] <= arr[i + 1];
}
}

/**
* BucketSort algorithms implements
* Sorts the given array using the Bucket Sort algorithm.
*
* @param arr the array contains elements
* @param arr the array to be sorted
* @return the sorted array
*/
public static int[] bucketSort(int[] arr) {
/* get max value of arr */
int max = max(arr);

/* get min value of arr */
int min = min(arr);
if (arr.length == 0) {
return arr;
}

/* number of buckets */
int min = Arrays.stream(arr).min().getAsInt();
int max = Arrays.stream(arr).max().getAsInt();
int numberOfBuckets = max - min + 1;

List<List<Integer>> buckets = new ArrayList<>(numberOfBuckets);
List<List<Integer>> buckets = initializeBuckets(numberOfBuckets);

/* init buckets */
for (int i = 0; i < numberOfBuckets; ++i) {
buckets.add(new ArrayList<>());
}

/* store elements to buckets */
for (int value : arr) {
int hash = hash(value, min, numberOfBuckets);
buckets.get(hash).add(value);
}
distributeElementsToBuckets(arr, buckets, min, numberOfBuckets);
sortBuckets(buckets);

/* sort individual bucket */
for (List<Integer> bucket : buckets) {
Collections.sort(bucket);
}
return concatenateBuckets(buckets, arr);
}

/* concatenate buckets to origin array */
int index = 0;
for (List<Integer> bucket : buckets) {
for (int value : bucket) {
arr[index++] = value;
}
}
/**
* Initializes the buckets for sorting.
*
* @param numberOfBuckets the number of buckets to initialize
* @return a list of empty buckets
*/
private static List<List<Integer>> initializeBuckets(final int numberOfBuckets) {
return IntStream.range(0, numberOfBuckets).mapToObj(i -> new ArrayList<Integer>()).collect(Collectors.toList());
}

return arr;
/**
* Distributes the elements of the array into the appropriate buckets.
*
* @param arr the array to distribute
* @param buckets the list of buckets
* @param min the minimum value in the array
* @param numberOfBuckets the total number of buckets
*/
private static void distributeElementsToBuckets(int[] arr, List<List<Integer>> buckets, final int min, final int numberOfBuckets) {
Arrays.stream(arr).forEach(value -> buckets.get(hash(value, min, numberOfBuckets)).add(value));
}

/**
* Get index of bucket which of our elements gets placed into it.
* Sorts each bucket individually.
*
* @param elem the element of array to be sorted
* @param min min value of array
* @param numberOfBucket the number of bucket
* @return index of bucket
* @param buckets the list of buckets to sort
*/
private static int hash(int elem, int min, int numberOfBucket) {
return (elem - min) / numberOfBucket;
private static void sortBuckets(List<List<Integer>> buckets) {
buckets.forEach(Collections::sort);
}

/**
* Calculate max value of array
* Concatenates the sorted buckets into the original array.
*
* @param arr the array contains elements
* @return max value of given array
* @param buckets the list of sorted buckets
* @param arr the original array
* @return the sorted array
*/
public static int max(int[] arr) {
int max = arr[0];
for (int value : arr) {
if (value > max) {
max = value;
private static int[] concatenateBuckets(List<List<Integer>> buckets, int[] arr) {
int index = 0;
for (List<Integer> bucket : buckets) {
for (int value : bucket) {
arr[index++] = value;
}
}
return max;
return arr;
}

/**
* Calculate min value of array
* Computes the hash value to determine which bucket an element should be placed in.
*
* @param arr the array contains elements
* @return min value of given array
* @param element the element of the array
* @param min the minimum value in the array
* @param numberOfBuckets the total number of buckets
* @return the index of the bucket
*/
public static int min(int[] arr) {
int min = arr[0];
for (int value : arr) {
if (value < min) {
min = value;
}
}
return min;
private static int hash(final int element, final int min, final int numberOfBuckets) {
return (element - min) / numberOfBuckets;
}
}
70 changes: 55 additions & 15 deletions src/test/java/com/thealgorithms/sorts/BucketSortTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,82 @@
public class BucketSortTest {

@Test
public void bucketSortSingleIntegerArray() {
public void sortSingleIntegerArray() {
int[] inputArray = {4};
int[] outputArray = BucketSort.bucketSort(inputArray);
int[] expectedOutput = {4};
assertArrayEquals(outputArray, expectedOutput);
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void bucketSortNonDuplicateIntegerArray() {
int[] inputArray = {6, 1, 99, 27, 15, 23, 36};
public void sortEmptyArray() {
int[] inputArray = {};
int[] expectedOutput = {};
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void sortAlreadySortedArray() {
int[] inputArray = {1, 2, 3, 4, 5, 6, 7};
int[] expectedOutput = {1, 2, 3, 4, 5, 6, 7};
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void sortNonDuplicateIntegerArray() {
int[] inputArray = {6, 1, 99, 27, 15, 23, 36};
int[] expectedOutput = {1, 6, 15, 23, 27, 36, 99};
assertArrayEquals(outputArray, expectedOutput);
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void bucketSortDuplicateIntegerArray() {
public void sortDuplicateIntegerArray() {
int[] inputArray = {6, 1, 27, 15, 23, 27, 36, 23};
int[] outputArray = BucketSort.bucketSort(inputArray);
int[] expectedOutput = {1, 6, 15, 23, 23, 27, 27, 36};
assertArrayEquals(outputArray, expectedOutput);
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void bucketSortNonDuplicateIntegerArrayWithNegativeNum() {
public void sortNonDuplicateIntegerArrayWithNegativeNum() {
int[] inputArray = {6, -1, 99, 27, -15, 23, -36};
int[] outputArray = BucketSort.bucketSort(inputArray);
int[] expectedOutput = {-36, -15, -1, 6, 23, 27, 99};
assertArrayEquals(outputArray, expectedOutput);
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void bucketSortDuplicateIntegerArrayWithNegativeNum() {
public void sortDuplicateIntegerArrayWithNegativeNum() {
int[] inputArray = {6, -1, 27, -15, 23, 27, -36, 23};
int[] outputArray = BucketSort.bucketSort(inputArray);
int[] expectedOutput = {-36, -15, -1, 6, 23, 23, 27, 27};
assertArrayEquals(outputArray, expectedOutput);
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void sortLargeArray() {
int[] inputArray = {100, 50, -100, 200, 0, 150, -50};
int[] expectedOutput = {-100, -50, 0, 50, 100, 150, 200};
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void sortArrayWithAllIdenticalElements() {
int[] inputArray = {5, 5, 5, 5, 5};
int[] expectedOutput = {5, 5, 5, 5, 5};
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}

@Test
public void sortArrayWithMixedPositiveAndNegativeNumbers() {
int[] inputArray = {-3, 0, 2, -2, 3, 1, -1};
int[] expectedOutput = {-3, -2, -1, 0, 1, 2, 3};
int[] outputArray = BucketSort.bucketSort(inputArray);
assertArrayEquals(expectedOutput, outputArray);
}
}