Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0c1f685

Browse files
committed
Add counting sort.
1 parent b1a613e commit 0c1f685

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ a set of rules that precisely defines a sequence of operations.
8080
* [Merge Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort)
8181
* [Quicksort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations
8282
* [Shellsort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/shell-sort)
83+
* [Counting Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/counting-sort)
8384
* **Tree**
8485
* [Depth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS)
8586
* [Breadth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/breadth-first-search) (BFS)
@@ -225,3 +226,4 @@ Below is the list of some of the most used Big O notations and their performance
225226
| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes |
226227
| **Quick sort** | n log(n) | n log(n) | n^2 | log(n) | No |
227228
| **Shell sort** | n log(n) | depends on gap sequence | n (log(n))^2 | 1 | No |
229+
| **Counting sort** | n + r | n + r | n + r | n + r | Yes |

‎src/algorithms/sorting/SortTester.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class SortTester {
1111
expect(sorter.sort([1])).toEqual([1]);
1212
expect(sorter.sort([1, 2])).toEqual([1, 2]);
1313
expect(sorter.sort([2, 1])).toEqual([1, 2]);
14+
expect(sorter.sort([3, 4, 2, 1, 0, 0, 4, 3, 4, 2])).toEqual([0, 0, 1, 2, 2, 3, 3, 4, 4, 4]);
1415
expect(sorter.sort(sortedArr)).toEqual(sortedArr);
1516
expect(sorter.sort(reverseArr)).toEqual(sortedArr);
1617
expect(sorter.sort(notSortedArr)).toEqual(sortedArr);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import Sort from '../Sort';
2+
3+
export default class CountingSort extends Sort {
4+
/**
5+
* @param {number[]} originalArray
6+
* @param {number} [biggestElement]
7+
*/
8+
sort(originalArray, biggestElement = 0) {
9+
// Detect biggest element in array in order to build in order to build
10+
// number bucket array later.
11+
let detectedBiggestElement = biggestElement;
12+
if (!detectedBiggestElement) {
13+
originalArray.forEach((element) => {
14+
// Visit element.
15+
this.callbacks.visitingCallback(element);
16+
17+
if (this.comparator.greaterThan(element, detectedBiggestElement)) {
18+
detectedBiggestElement = element;
19+
}
20+
});
21+
}
22+
23+
// Init buckets array.
24+
// This array will hold frequency of each number from originalArray.
25+
const buckets = Array(detectedBiggestElement + 1).fill(0);
26+
originalArray.forEach((element) => {
27+
// Visit element.
28+
this.callbacks.visitingCallback(element);
29+
30+
buckets[element] += 1;
31+
});
32+
33+
// Add previous frequencies to the current one for each number in bucket
34+
// to detect how many numbers less then current one should be standing to
35+
// the left of current one.
36+
for (let bucketIndex = 1; bucketIndex < buckets.length; bucketIndex += 1) {
37+
buckets[bucketIndex] += buckets[bucketIndex - 1];
38+
}
39+
40+
// Now let's shift frequencies to the right so that they show correct numbers.
41+
// I.e. if we won't shift right than the value of buckets[5] will display how many
42+
// elements less than 5 should be placed to the left of 5 in sorted array
43+
// INCLUDING 5th. After shifting though this number will not include 5th anymore.
44+
buckets.pop();
45+
buckets.unshift(0);
46+
47+
// Now let's assemble sorted array.
48+
const sortedArray = Array(originalArray.length).fill(null);
49+
for (let elementIndex = 0; elementIndex < originalArray.length; elementIndex += 1) {
50+
// Get the element that we want to put into correct sorted position.
51+
const element = originalArray[elementIndex];
52+
53+
// Visit element.
54+
this.callbacks.visitingCallback(element);
55+
56+
// Get correct position of this element in sorted array.
57+
const elementSortedPosition = buckets[element];
58+
59+
// Put element into correct position in sorted array.
60+
sortedArray[elementSortedPosition] = element;
61+
62+
// Increase position of current element in the bucket for future correct placements.
63+
buckets[element] += 1;
64+
}
65+
66+
// Return sorted array.
67+
return sortedArray;
68+
}
69+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Counting Sort
2+
3+
In computer science, **counting sort** is an algorithm for sorting
4+
a collection of objects according to keys that are small integers;
5+
that is, it is an integer sorting algorithm. It operates by
6+
counting the number of objects that have each distinct key value,
7+
and using arithmetic on those counts to determine the positions
8+
of each key value in the output sequence. Its running time is
9+
linear in the number of items and the difference between the
10+
maximum and minimum key values, so it is only suitable for direct
11+
use in situations where the variation in keys is not significantly
12+
greater than the number of items. However, it is often used as a
13+
subroutine in another sorting algorithm, radix sort, that can
14+
handle larger keys more efficiently.
15+
16+
Because counting sort uses key values as indexes into an array,
17+
it is not a comparison sort, and the `Ω(n log n)` lower bound for
18+
comparison sorting does not apply to it. Bucket sort may be used
19+
for many of the same tasks as counting sort, with a similar time
20+
analysis; however, compared to counting sort, bucket sort requires
21+
linked lists, dynamic arrays or a large amount of preallocated
22+
memory to hold the sets of items within each bucket, whereas
23+
counting sort instead stores a single number (the count of items)
24+
per bucket.
25+
26+
Counting sorting works best when the range of numbers for each array
27+
element is very small.
28+
29+
## Algorithm
30+
31+
**Step I**
32+
33+
In first step we calculate the count of all the elements of the
34+
input array `A`. Then Store the result in the count array `C`.
35+
The way we count is depected below.
36+
37+
![Counting Sort](https://3.bp.blogspot.com/-jJchly1BkTc/WLGqCFDdvCI/AAAAAAAAAHA/luljAlz2ptMndIZNH0KLTTuQMNsfzDeFQCLcB/s1600/CSortUpdatedStepI.gif)
38+
39+
**Step II**
40+
41+
In second step we calculate how many elements exist in the input
42+
array `A` which are less than or equals for the given index.
43+
`Ci` = numbers of elements less than or equals to `i` in input array.
44+
45+
![Counting Sort](https://1.bp.blogspot.com/-1vFu-VIRa9Y/WLHGuZkdF3I/AAAAAAAAAHs/8jKu2dbQee4ap9xlVcNsILrclqw0UxAVACLcB/s1600/Step-II.png)
46+
47+
**Step III**
48+
49+
In this step we place the input array `A` element at sorted
50+
position by taking help of constructed count array `C` ,i.e what
51+
we constructed in step two. We used the result array `B` to store
52+
the sorted elements. Here we handled the index of `B` start from
53+
zero.
54+
55+
![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif)
56+
57+
## References
58+
59+
- [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort)
60+
- [YouTube](https://www.youtube.com/watch?v=OKd534EWcdk&index=61&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
61+
- [EfficientAlgorithms](https://efficientalgorithms.blogspot.com/2016/09/lenear-sorting-counting-sort.html)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import CountingSort from '../CountingSort';
2+
import {
3+
equalArr,
4+
notSortedArr,
5+
reverseArr,
6+
sortedArr,
7+
SortTester,
8+
} from '../../SortTester';
9+
10+
// Complexity constants.
11+
const SORTED_ARRAY_VISITING_COUNT = 60;
12+
const NOT_SORTED_ARRAY_VISITING_COUNT = 60;
13+
const REVERSE_SORTED_ARRAY_VISITING_COUNT = 60;
14+
const EQUAL_ARRAY_VISITING_COUNT = 60;
15+
16+
describe('CountingSort', () => {
17+
it('should sort array', () => {
18+
SortTester.testSort(CountingSort);
19+
});
20+
21+
it('should allow to use specify maximum integer value in array to make sorting faster', () => {
22+
const visitingCallback = jest.fn();
23+
const sorter = new CountingSort({ visitingCallback });
24+
25+
// Detect biggest number in array in prior.
26+
const biggestElement = notSortedArr.reduce((accumulator, element) => {
27+
return element > accumulator ? element : accumulator;
28+
}, 0);
29+
30+
const sortedArray = sorter.sort(notSortedArr, biggestElement);
31+
32+
expect(sortedArray).toEqual(sortedArr);
33+
// Normally visitingCallback is being called 60 times but in this case
34+
// it should be called only 40 times.
35+
expect(visitingCallback).toHaveBeenCalledTimes(40);
36+
});
37+
38+
it('should visit EQUAL array element specified number of times', () => {
39+
SortTester.testAlgorithmTimeComplexity(
40+
CountingSort,
41+
equalArr,
42+
EQUAL_ARRAY_VISITING_COUNT,
43+
);
44+
});
45+
46+
it('should visit SORTED array element specified number of times', () => {
47+
SortTester.testAlgorithmTimeComplexity(
48+
CountingSort,
49+
sortedArr,
50+
SORTED_ARRAY_VISITING_COUNT,
51+
);
52+
});
53+
54+
it('should visit NOT SORTED array element specified number of times', () => {
55+
SortTester.testAlgorithmTimeComplexity(
56+
CountingSort,
57+
notSortedArr,
58+
NOT_SORTED_ARRAY_VISITING_COUNT,
59+
);
60+
});
61+
62+
it('should visit REVERSE SORTED array element specified number of times', () => {
63+
SortTester.testAlgorithmTimeComplexity(
64+
CountingSort,
65+
reverseArr,
66+
REVERSE_SORTED_ARRAY_VISITING_COUNT,
67+
);
68+
});
69+
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /