Skip to content

Commit 7e3a3cd

Browse files
authored
Added counting sort (#280)
1 parent 5f5e386 commit 7e3a3cd

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

pydatastructs/linear_data_structures/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
brick_sort,
2727
brick_sort_parallel,
2828
heapsort,
29-
matrix_multiply_parallel
29+
matrix_multiply_parallel,
30+
counting_sort
3031
)
3132
__all__.extend(algorithms.__all__)

pydatastructs/linear_data_structures/algorithms.py

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from pydatastructs.linear_data_structures.arrays import (
2-
OneDimensionalArray, DynamicArray)
2+
OneDimensionalArray, DynamicArray, Array)
33
from pydatastructs.utils.misc_util import _check_type, _comp
44
from concurrent.futures import ThreadPoolExecutor
55
from math import log, floor
@@ -9,7 +9,8 @@
99
'brick_sort',
1010
'brick_sort_parallel',
1111
'heapsort',
12-
'matrix_multiply_parallel'
12+
'matrix_multiply_parallel',
13+
'counting_sort'
1314
]
1415

1516
def _merge(array, sl, el, sr, er, end, comp):
@@ -294,6 +295,83 @@ def heapsort(array, **kwargs):
294295
if _check_type(array, DynamicArray):
295296
array._modify(force=True)
296297

298+
def counting_sort(array: Array) -> Array:
299+
"""
300+
Performs counting sort on the given array.
301+
302+
Parameters
303+
==========
304+
305+
array: Array
306+
The array which is to be sorted.
307+
308+
Returns
309+
=======
310+
311+
output: Array
312+
The sorted array.
313+
314+
Examples
315+
========
316+
317+
>>> from pydatastructs import DynamicOneDimensionalArray as DODA, counting_sort
318+
>>> arr = DODA(int, [5, 78, 1, 0])
319+
>>> out = counting_sort(arr)
320+
>>> str(out)
321+
"['0', '1', '5', '78']"
322+
>>> arr.delete(2)
323+
>>> out = counting_sort(arr)
324+
>>> str(out)
325+
"['0', '5', '78']"
326+
327+
References
328+
==========
329+
330+
.. [1] https://en.wikipedia.org/wiki/Counting_sort
331+
332+
Note
333+
====
334+
335+
Since, counting sort is a non-comparison sorting algorithm,
336+
custom comparators aren't allowed.
337+
The ouput array doesn't contain any `None` value.
338+
"""
339+
max_val, min_val = array[0], array[0]
340+
none_count = 0
341+
for i in range(len(array)):
342+
if array[i] is not None:
343+
if max_val is None or max_val < array[i]:
344+
max_val = array[i]
345+
if min_val is None or array[i] < min_val:
346+
min_val = array[i]
347+
else:
348+
none_count += 1
349+
if min_val is None or max_val is None:
350+
return array
351+
352+
count = [0 for _ in range(max_val - min_val + 1)]
353+
for i in range(len(array)):
354+
if array[i] is not None:
355+
count[array[i] - min_val] += 1
356+
357+
total = 0
358+
for i in range(max_val - min_val + 1):
359+
count[i], total = total, count[i] + total
360+
361+
output = type(array)(array._dtype,
362+
[array[i] for i in range(len(array))
363+
if array[i] is not None])
364+
if _check_type(output, DynamicArray):
365+
output._modify(force=True)
366+
367+
for i in range(len(array)):
368+
x = array[i]
369+
if x is not None:
370+
output[count[x-min_val]] = x
371+
count[x-min_val] += 1
372+
373+
return output
374+
297375
def _matrix_multiply_helper(m1, m2, row, col):
298376
s = 0
299377
for i in range(len(m1)):

pydatastructs/linear_data_structures/tests/test_algorithms.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pydatastructs import (
22
merge_sort_parallel, DynamicOneDimensionalArray,
33
OneDimensionalArray, brick_sort, brick_sort_parallel,
4-
heapsort, matrix_multiply_parallel)
4+
heapsort, matrix_multiply_parallel, counting_sort)
55
from pydatastructs.utils.raises_util import raises
66
import random
77

@@ -53,6 +53,20 @@ def test_brick_sort_parallel():
5353
def test_heapsort():
5454
_test_common_sort(heapsort)
5555

56+
def test_counting_sort():
57+
random.seed(1000)
58+
59+
n = random.randint(10, 20)
60+
arr = DynamicOneDimensionalArray(int, 0)
61+
for _ in range(n):
62+
arr.append(random.randint(1, 1000))
63+
for _ in range(n//3):
64+
arr.delete(random.randint(0, n//2))
65+
66+
expected_arr = [102, 134, 228, 247, 362, 373, 448,
67+
480, 548, 686, 688, 696, 779]
68+
assert counting_sort(arr)._data == expected_arr
69+
5670
def test_matrix_multiply_parallel():
5771
ODA = OneDimensionalArray
5872

0 commit comments

Comments
 (0)