Skip to content

Commit 0ed5b40

Browse files
committed
feat: implements counting sort algorithm
1 parent f68da12 commit 0ed5b40

File tree

6 files changed

+252
-1
lines changed

6 files changed

+252
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Demos can be found at: http://tylerhawkins.info/js-data-structures-and-algorithm
6868
### Sorting
6969

7070
- [Bubble Sort](src/algorithms/sort/bubble-sort/src/bubble-sort.js)
71-
- Counting Sort (TODO)
71+
- [Counting Sort](src/algorithms/sort/counting-sort/src/counting-sort.js)
7272
- Heap Sort (TODO)
7373
- [Insertion Sort](src/algorithms/sort/insertion-sort/src/insertion-sort.js)
7474
- [Merge Sort](src/algorithms/sort/merge-sort/src/merge-sort.js)

src/algorithms/sort/additional-demos/sort-performance-comparison-test.demo.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component } from 'react'
22
import './sort-performance-comparison-test.demo.css'
33
import { bubbleSort } from '../bubble-sort/src/bubble-sort'
4+
import { countingSort } from '../counting-sort/src/counting-sort'
45
import { insertionSort } from '../insertion-sort/src/insertion-sort'
56
import { mergeSort } from '../merge-sort/src/merge-sort'
67
import { quickSort } from '../quick-sort/src/quick-sort'
@@ -149,6 +150,11 @@ class SortPerformanceComparisonTest extends Component {
149150
bubbleSort(initialArrayCopy)
150151
const endTimeForBubbleSort = performance.now()
151152

153+
initialArrayCopy = [...storedArrays[arrayKey].initialArray]
154+
const startTimeForCountingSort = performance.now()
155+
countingSort(initialArrayCopy)
156+
const endTimeForCountingSort = performance.now()
157+
152158
initialArrayCopy = [...storedArrays[arrayKey].initialArray]
153159
const startTimeForInsertionSort = performance.now()
154160
insertionSort(initialArrayCopy)
@@ -177,6 +183,7 @@ class SortPerformanceComparisonTest extends Component {
177183
...prevState.storedArrays[arrayKey],
178184
timeTaken: {
179185
bubbleSort: endTimeForBubbleSort - startTimeForBubbleSort,
186+
countingSort: endTimeForCountingSort - startTimeForCountingSort,
180187
insertionSort: endTimeForInsertionSort - startTimeForInsertionSort,
181188
mergeSort: endTimeForMergeSort - startTimeForMergeSort,
182189
quickSort: endTimeForQuickSort - startTimeForQuickSort,
@@ -268,6 +275,22 @@ class SortPerformanceComparisonTest extends Component {
268275
seconds).
269276
</div>
270277
<hr />
278+
<div>
279+
<h3>Counting Sort </h3> took{' '}
280+
<b>
281+
{storedArrays[
282+
currentResultKey
283+
].timeTaken.countingSort.toFixed(3)}
284+
</b>{' '}
285+
milliseconds (or{' '}
286+
<b>
287+
{(
288+
storedArrays[currentResultKey].timeTaken.countingSort / 1000
289+
).toFixed(6)}
290+
</b>{' '}
291+
seconds).
292+
</div>
293+
<hr />
271294
<div>
272295
<h3>Insertion Sort </h3> took{' '}
273296
<b>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react'
2+
import { countingSort } from '../src/counting-sort'
3+
import { SortPerformanceTest } from '../../demo-utils/sort-performance-test.demo'
4+
5+
export default {
6+
title: 'Algorithms/Sort/Counting Sort',
7+
}
8+
9+
export const countingSortPerformanceTest = () => (
10+
<SortPerformanceTest
11+
sortMethodName="Counting Sort"
12+
sortMethod={countingSort}
13+
/>
14+
)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Counting Sort
3+
*
4+
* Compares each pair of adjacent items and swaps them if they are in the wrong order
5+
* Continues looping through the array until no more swaps are needed
6+
* Not appropriate for large unsorted data sets
7+
*
8+
* Best case performance: Ω(n + k) (always loops through the input array, count array, and output array)
9+
* Average case performance: θ(n + k) (always loops through the input array, count array, and output array)
10+
* Worst case performance: O(n + k) (always loops through the input array, count array, and output array)
11+
*
12+
* Space required: O(n + k)
13+
*/
14+
15+
export const countingSort = (arr, minValue, maxValue, showLogs) => {
16+
const sortedArr = []
17+
const countArr = []
18+
let min = minValue
19+
let max = maxValue
20+
21+
/* istanbul ignore next */
22+
showLogs && console.log(`starting array: ${arr.join(' ')}`)
23+
24+
if (typeof min === 'undefined' || typeof max === 'undefined') {
25+
/* istanbul ignore next */
26+
showLogs && console.log('getting min and max values of the input array')
27+
28+
for (let i = 0; i < arr.length; i++) {
29+
const currentElement = arr[i]
30+
31+
if (i === 0) {
32+
min = currentElement
33+
max = currentElement
34+
}
35+
36+
if (currentElement < min) {
37+
min = currentElement
38+
}
39+
40+
if (currentElement > max) {
41+
max = currentElement
42+
}
43+
}
44+
}
45+
46+
/* istanbul ignore next */
47+
showLogs && console.log(`min value: ${min}; max value: ${max}`)
48+
49+
const countRange = max - min + 1
50+
for (let i = 0; i < countRange; i++) {
51+
countArr.push(0)
52+
}
53+
54+
/* istanbul ignore next */
55+
showLogs && console.log(`initialized count array: ${countArr.join(' ')}`)
56+
57+
for (let i = 0; i < arr.length; i++) {
58+
const currentElement = arr[i]
59+
countArr[currentElement - min]++
60+
}
61+
62+
/* istanbul ignore next */
63+
showLogs && console.log(`populated count array: ${countArr.join(' ')}`)
64+
65+
for (let i = 0; i < countArr.length; i++) {
66+
while (countArr[i] > 0) {
67+
sortedArr.push(i + min)
68+
countArr[i]--
69+
}
70+
}
71+
72+
/* istanbul ignore next */
73+
showLogs && console.log(`sorted output array: ${sortedArr.join(' ')}`)
74+
75+
return sortedArr
76+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { countingSort } from './counting-sort'
2+
3+
const showLogs = process.env.SHOW_LOGS === '1'
4+
5+
describe('countingSort', () => {
6+
describe('non-negative integers in the input array', () => {
7+
it('correctly sorts an unsorted array', () => {
8+
const arrayToSort = [3, 6, 2, 8, 9, 1, 4, 5, 7]
9+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
10+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
11+
expectedResult
12+
)
13+
})
14+
15+
it('correctly sorts a mostly sorted array', () => {
16+
const arrayToSort = [1, 2, 9, 3, 4, 5, 6, 7, 8]
17+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
18+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
19+
expectedResult
20+
)
21+
})
22+
23+
it('correctly sorts an inversely sorted array', () => {
24+
const arrayToSort = [9, 8, 7, 6, 5, 4, 3, 2, 1]
25+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
26+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
27+
expectedResult
28+
)
29+
})
30+
31+
it('correctly returns an already sorted array', () => {
32+
const arrayToSort = [1, 2, 3, 4, 5, 6, 7, 8, 9]
33+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
34+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
35+
expectedResult
36+
)
37+
})
38+
39+
it('can handle an array with duplicates', () => {
40+
const arrayToSort = [3, 6, 2, 8, 4, 4, 4, 4, 7]
41+
const expectedResult = [2, 3, 4, 4, 4, 4, 6, 7, 8]
42+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
43+
expectedResult
44+
)
45+
})
46+
47+
it('can handle an array with only one item', () => {
48+
const arrayToSort = [1]
49+
const expectedResult = [1]
50+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
51+
expectedResult
52+
)
53+
})
54+
55+
it('can handle an empty array', () => {
56+
const arrayToSort = []
57+
const expectedResult = []
58+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
59+
expectedResult
60+
)
61+
})
62+
})
63+
64+
describe('negative integers in the input array', () => {
65+
it('correctly sorts an unsorted array', () => {
66+
const arrayToSort = [3, 6, 2, 8, -2, 9, 1, 4, -1, 5, 10, 0, 7]
67+
const expectedResult = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
68+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
69+
expectedResult
70+
)
71+
})
72+
73+
it('correctly sorts a mostly sorted array', () => {
74+
const arrayToSort = [-2, -1, 0, 1, 2, 9, 3, 4, 5, 6, 7, 8, 10]
75+
const expectedResult = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
76+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
77+
expectedResult
78+
)
79+
})
80+
81+
it('correctly sorts an inversely sorted array', () => {
82+
const arrayToSort = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2]
83+
const expectedResult = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
84+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
85+
expectedResult
86+
)
87+
})
88+
89+
it('correctly returns an already sorted array', () => {
90+
const arrayToSort = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
91+
const expectedResult = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
92+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
93+
expectedResult
94+
)
95+
})
96+
97+
it('can handle an array with duplicates', () => {
98+
const arrayToSort = [3, 6, -1, -1, 2, 8, 4, 4, 10, 4, -1, 4, 7]
99+
const expectedResult = [-1, -1, -1, 2, 3, 4, 4, 4, 4, 6, 7, 8, 10]
100+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
101+
expectedResult
102+
)
103+
})
104+
105+
it('can handle an array with only one item', () => {
106+
const arrayToSort = [-1]
107+
const expectedResult = [-1]
108+
expect(countingSort(arrayToSort, undefined, undefined, showLogs)).toEqual(
109+
expectedResult
110+
)
111+
})
112+
})
113+
114+
describe('min and max value arguments', () => {
115+
it('uses the provided minValue and maxValue arguments when provided', () => {
116+
const arrayToSort = [3, 6, 2, 8, 9, 1, 4, 5, 7]
117+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
118+
expect(countingSort(arrayToSort, 1, 9, showLogs)).toEqual(expectedResult)
119+
})
120+
121+
it('calculates the min and max if only the minValue argument is provided', () => {
122+
const arrayToSort = [3, 6, 2, 8, 9, 1, 4, 5, 7]
123+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
124+
expect(countingSort(arrayToSort, 1, undefined, showLogs)).toEqual(
125+
expectedResult
126+
)
127+
})
128+
129+
it('calculates the min and max if only the maxValue argument is provided', () => {
130+
const arrayToSort = [3, 6, 2, 8, 9, 1, 4, 5, 7]
131+
const expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9]
132+
expect(countingSort(arrayToSort, undefined, 9, showLogs)).toEqual(
133+
expectedResult
134+
)
135+
})
136+
})
137+
})

src/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export { union } from './algorithms/set/union/src/union'
1818

1919
// Sort
2020
export { bubbleSort } from './algorithms/sort/bubble-sort/src/bubble-sort'
21+
export { countingSort } from './algorithms/sort/counting-sort/src/counting-sort'
2122
export { insertionSort } from './algorithms/sort/insertion-sort/src/insertion-sort'
2223
export { mergeSort } from './algorithms/sort/merge-sort/src/merge-sort'
2324
export { quickSort } from './algorithms/sort/quick-sort/src/quick-sort'

0 commit comments

Comments
 (0)