Skip to content

Commit 1ad60dc

Browse files
committedMar 13, 2023
Add Bucket Sort.
1 parent e95d856 commit 1ad60dc

File tree

8 files changed

+134
-19
lines changed

8 files changed

+134
-19
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ a set of rules that precisely define a sequence of operations.
133133
* `B` [Shellsort](src/algorithms/sorting/shell-sort)
134134
* `B` [Counting Sort](src/algorithms/sorting/counting-sort)
135135
* `B` [Radix Sort](src/algorithms/sorting/radix-sort)
136+
* `B` [Bucket Sort](src/algorithms/sorting/bucket-sort)
136137
* **Linked Lists**
137138
* `B` [Straight Traversal](src/algorithms/linked-list/traversal)
138139
* `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import RadixSort from '../radix-sort/RadixSort';
2+
3+
/**
4+
* Bucket Sort
5+
*
6+
* @param {number[]} arr
7+
* @param {number} bucketsNum
8+
* @return {number[]}
9+
*/
10+
export default function BucketSort(arr, bucketsNum = 1) {
11+
const buckets = new Array(bucketsNum).fill(null).map(() => []);
12+
13+
const minValue = Math.min(...arr);
14+
const maxValue = Math.max(...arr);
15+
16+
const bucketSize = Math.ceil(Math.max(1, (maxValue - minValue) / bucketsNum));
17+
18+
// Place elements into buckets.
19+
for (let i = 0; i < arr.length; i += 1) {
20+
const currValue = arr[i];
21+
const bucketIndex = Math.floor((currValue - minValue) / bucketSize);
22+
23+
// Edge case for max value.
24+
if (bucketIndex === bucketsNum) {
25+
buckets[bucketsNum - 1].push(currValue);
26+
} else {
27+
buckets[bucketIndex].push(currValue);
28+
}
29+
}
30+
31+
// Sort individual buckets.
32+
for (let i = 0; i < buckets.length; i += 1) {
33+
// Let's use the Radix Sorter here. This may give us
34+
// the average O(n + k) time complexity to sort one bucket
35+
// (where k is a number of digits in the longest number).
36+
buckets[i] = new RadixSort().sort(buckets[i]);
37+
}
38+
39+
// Merge sorted buckets into final output.
40+
const sortedArr = [];
41+
for (let i = 0; i < buckets.length; i += 1) {
42+
sortedArr.push(...buckets[i]);
43+
}
44+
45+
return sortedArr;
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Bucket Sort
2+
3+
**Bucket sort**, or **bin sort**, is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm.
4+
5+
## Algorithm
6+
7+
Bucket sort works as follows:
8+
9+
1. Set up an array of initially empty `buckets`.
10+
2. **Scatter:** Go over the original array, putting each object in its `bucket`.
11+
3. Sort each non-empty `bucket`.
12+
4. **Gather:** Visit the `buckets` in order and put all elements back into the original array.
13+
14+
Elements are distributed among bins:
15+
16+
![Elements are distributed among bins](./images/bucket_sort_1.png)
17+
18+
Then, elements are sorted within each bin:
19+
20+
![Elements are sorted within each bin](./images/bucket_sort_2.png)
21+
22+
23+
## Complexity
24+
25+
The computational complexity depends on the algorithm used to sort each bucket, the number of buckets to use, and whether the input is uniformly distributed.
26+
27+
The **worst-case** time complexity of bucket sort is
28+
`O(n^2)` if the sorting algorithm used on the bucket is *insertion sort*, which is the most common use case since the expectation is that buckets will not have too many elements relative to the entire list. In the worst case, all elements are placed in one bucket, causing the running time to reduce to the worst-case complexity of insertion sort (all elements are in reverse order). If the worst-case running time of the intermediate sort used is `O(n * log(n))`, then the worst-case running time of bucket sort will also be
29+
`O(n * log(n))`.
30+
31+
On **average**, when the distribution of elements across buckets is reasonably uniform, it can be shown that bucket sort runs on average `O(n + k)` for `k` buckets.
32+
33+
## References
34+
35+
- [Bucket Sort on Wikipedia](https://en.wikipedia.org/wiki/Bucket_sort)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import BucketSort from '../BucketSort';
2+
import {
3+
equalArr,
4+
notSortedArr,
5+
reverseArr,
6+
sortedArr,
7+
} from '../../SortTester';
8+
9+
describe('BucketSort', () => {
10+
it('should sort the array of numbers with different buckets amounts', () => {
11+
expect(BucketSort(notSortedArr, 4)).toEqual(sortedArr);
12+
expect(BucketSort(equalArr, 4)).toEqual(equalArr);
13+
expect(BucketSort(reverseArr, 4)).toEqual(sortedArr);
14+
expect(BucketSort(sortedArr, 4)).toEqual(sortedArr);
15+
16+
expect(BucketSort(notSortedArr, 10)).toEqual(sortedArr);
17+
expect(BucketSort(equalArr, 10)).toEqual(equalArr);
18+
expect(BucketSort(reverseArr, 10)).toEqual(sortedArr);
19+
expect(BucketSort(sortedArr, 10)).toEqual(sortedArr);
20+
21+
expect(BucketSort(notSortedArr, 50)).toEqual(sortedArr);
22+
expect(BucketSort(equalArr, 50)).toEqual(equalArr);
23+
expect(BucketSort(reverseArr, 50)).toEqual(sortedArr);
24+
expect(BucketSort(sortedArr, 50)).toEqual(sortedArr);
25+
});
26+
27+
it('should sort the array of numbers with the default buckets of 1', () => {
28+
expect(BucketSort(notSortedArr)).toEqual(sortedArr);
29+
expect(BucketSort(equalArr)).toEqual(equalArr);
30+
expect(BucketSort(reverseArr)).toEqual(sortedArr);
31+
expect(BucketSort(sortedArr)).toEqual(sortedArr);
32+
});
33+
});
Loading
Loading

‎src/algorithms/sorting/radix-sort/README.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,37 @@
33
_Read this in other languages:_
44
[_Português_](README.pt-BR.md),
55

6-
In computer science, **radix sort** is a non-comparative integer sorting
7-
algorithm that sorts data with integer keys by grouping keys by the individual
6+
In computer science, **radix sort** is a non-comparative integer sorting
7+
algorithm that sorts data with integer keys by grouping keys by the individual
88
digits which share the same significant position and value. A positional notation
9-
is required, but because integers can represent strings of characters
10-
(e.g., names or dates) and specially formatted floating point numbers, radix
9+
is required, but because integers can represent strings of characters
10+
(e.g., names or dates) and specially formatted floating point numbers, radix
1111
sort is not limited to integers.
1212

1313
*Where does the name come from?*
1414

1515
In mathematical numeral systems, the *radix* or base is the number of unique digits,
16-
including the digit zero, used to represent numbers in a positional numeral system.
17-
For example, a binary system (using numbers 0 and 1) has a radix of 2 and a decimal
16+
including the digit zero, used to represent numbers in a positional numeral system.
17+
For example, a binary system (using numbers 0 and 1) has a radix of 2 and a decimal
1818
system (using numbers 0 to 9) has a radix of 10.
1919

2020
## Efficiency
2121

22-
The topic of the efficiency of radix sort compared to other sorting algorithms is
23-
somewhat tricky and subject to quite a lot of misunderstandings. Whether radix
24-
sort is equally efficient, less efficient or more efficient than the best
25-
comparison-based algorithms depends on the details of the assumptions made.
26-
Radix sort complexity is `O(wn)` for `n` keys which are integers of word size `w`.
27-
Sometimes `w` is presented as a constant, which would make radix sort better
28-
(for sufficiently large `n`) than the best comparison-based sorting algorithms,
29-
which all perform `O(n log n)` comparisons to sort `n` keys. However, in
30-
general `w` cannot be considered a constant: if all `n` keys are distinct,
31-
then `w` has to be at least `log n` for a random-access machine to be able to
32-
store them in memory, which gives at best a time complexity `O(n log n)`. That
33-
would seem to make radix sort at most equally efficient as the best
22+
The topic of the efficiency of radix sort compared to other sorting algorithms is
23+
somewhat tricky and subject to quite a lot of misunderstandings. Whether radix
24+
sort is equally efficient, less efficient or more efficient than the best
25+
comparison-based algorithms depends on the details of the assumptions made.
26+
Radix sort complexity is `O(wn)` for `n` keys which are integers of word size `w`.
27+
Sometimes `w` is presented as a constant, which would make radix sort better
28+
(for sufficiently large `n`) than the best comparison-based sorting algorithms,
29+
which all perform `O(n log n)` comparisons to sort `n` keys. However, in
30+
general `w` cannot be considered a constant: if all `n` keys are distinct,
31+
then `w` has to be at least `log n` for a random-access machine to be able to
32+
store them in memory, which gives at best a time complexity `O(n log n)`. That
33+
would seem to make radix sort at most equally efficient as the best
3434
comparison-based sorts (and worse if keys are much longer than `log n`).
3535

36-
![Radix Sort](https://www.researchgate.net/publication/291086231/figure/fig1/AS:614214452404240@1523451545568/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the.png)
36+
![Radix Sort](./images/radix-sort.png)
3737

3838
## Complexity
3939

Loading

0 commit comments

Comments
 (0)
Please sign in to comment.