Skip to content

Commit 1e8a76a

Browse files
committed
fixes:codezonediitj#603 Radix Sort
1 parent f34b7d6 commit 1e8a76a

File tree

2 files changed

+150
-2
lines changed

2 files changed

+150
-2
lines changed

pydatastructs/linear_data_structures/algorithms.py

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
'jump_search',
3131
'selection_sort',
3232
'insertion_sort',
33-
'intro_sort'
33+
'intro_sort',
34+
'radix_sort'
3435
]
3536

3637
def _merge(array, sl, el, sr, er, end, comp):
@@ -1843,6 +1844,111 @@ def partition(array, lower, upper):
18431844
elif maxdepth == 0:
18441845
heapsort(array, start=lower, end=upper)
18451846
return array
1847+
1848+
def radix_sort(array: Array, **kwargs) -> Array:
1849+
"""
1850+
Performs radix sort on the given array of non-negative integers.
1851+
Uses counting sort as a subroutine to sort by each digit position.
1852+
1853+
Parameters
1854+
==========
1855+
1856+
array: Array
1857+
The array which is to be sorted. Must contain only non-negative integers.
1858+
start: int
1859+
The starting index of the portion
1860+
which is to be sorted.
1861+
Optional, by default 0
1862+
end: int
1863+
The ending index of the portion which
1864+
is to be sorted.
1865+
Optional, by default the index
1866+
of the last position filled.
1867+
backend: pydatastructs.Backend
1868+
The backend to be used.
1869+
Optional, by default, the best available
1870+
backend is used.
1871+
1872+
Returns
1873+
=======
1874+
1875+
output: Array
1876+
The sorted array.
1877+
1878+
Examples
1879+
========
1880+
1881+
>>> from pydatastructs import OneDimensionalArray, radix_sort
1882+
>>> arr = OneDimensionalArray(int,[170, 45, 75, 90, 802, 24, 2, 66])
1883+
>>> out = radix_sort(arr)
1884+
>>> str(out)
1885+
'[2, 24, 45, 66, 75, 90, 170, 802]'
1886+
1887+
References
1888+
==========
1889+
1890+
.. [1] https://en.wikipedia.org/wiki/Radix_sort
1891+
1892+
Note
1893+
====
1894+
1895+
This implementation:
1896+
1. Only works with non-negative integers
1897+
2. Uses LSD (Least Significant Digit) radix sort
1898+
3. Uses base-10 digits
1899+
"""
1900+
raise_if_backend_is_not_python(
1901+
radix_sort, kwargs.get('backend', Backend.PYTHON))
1902+
1903+
# Find maximum number to know number of digits
1904+
max_val = 0
1905+
start = kwargs.get('start', 0)
1906+
end = kwargs.get('end', len(array) - 1)
1907+
1908+
for i in range(start, end + 1):
1909+
if array[i] is not None and array[i] > max_val:
1910+
max_val = array[i]
1911+
1912+
# Do counting sort for every digit
1913+
exp = 1
1914+
while max_val // exp > 0:
1915+
# Create output array with same type as input
1916+
output = type(array)(array._dtype, [array[i] for i in range(len(array))])
1917+
if _check_type(output, DynamicArray):
1918+
output._modify(force=True)
1919+
1920+
# Store count of occurrences
1921+
count = [0] * 10
1922+
1923+
# Count occurrences of current digit
1924+
for i in range(start, end + 1):
1925+
if array[i] is not None:
1926+
idx = (array[i] // exp) % 10
1927+
count[idx] += 1
1928+
1929+
# Change count[i] to position of digit in output
1930+
for i in range(1, 10):
1931+
count[i] += count[i - 1]
1932+
1933+
# Build output array
1934+
i = end
1935+
while i >= start:
1936+
if array[i] is not None:
1937+
idx = (array[i] // exp) % 10
1938+
output[start + count[idx] - 1] = array[i]
1939+
count[idx] -= 1
1940+
i -= 1
1941+
1942+
# Copy output array to array
1943+
for i in range(start, end + 1):
1944+
array[i] = output[i]
1945+
1946+
exp *= 10
1947+
1948+
if _check_type(array, (DynamicArray, _arrays.DynamicOneDimensionalArray)):
1949+
array._modify(True)
1950+
1951+
return array
18461952
else:
18471953
p = partition(array, lower, upper)
18481954

pydatastructs/linear_data_structures/tests/test_algorithms.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
cocktail_shaker_sort, quick_sort, longest_common_subsequence, is_ordered,
66
upper_bound, lower_bound, longest_increasing_subsequence, next_permutation,
77
prev_permutation, bubble_sort, linear_search, binary_search, jump_search,
8-
selection_sort, insertion_sort, intro_sort, Backend)
8+
selection_sort, insertion_sort, intro_sort, Backend, radix_sort)
99

1010
from pydatastructs.utils.raises_util import raises
1111
import random
@@ -414,3 +414,45 @@ def test_binary_search():
414414
def test_jump_search():
415415
_test_common_search(jump_search)
416416
_test_common_search(jump_search, backend=Backend.CPP)
417+
418+
def test_radix_sort():
419+
random.seed(1000)
420+
421+
# Test with DynamicOneDimensionalArray
422+
n = random.randint(10, 20)
423+
arr = DynamicOneDimensionalArray(int, 0)
424+
for _ in range(n):
425+
arr.append(random.randint(1, 1000))
426+
for _ in range(n//3):
427+
arr.delete(random.randint(0, n//2))
428+
429+
# Test full array sort
430+
expected_arr = [102, 134, 228, 247, 362, 373, 448,
431+
480, 548, 686, 688, 696, 779]
432+
assert radix_sort(arr)._data == expected_arr
433+
434+
# Test with OneDimensionalArray
435+
arr = OneDimensionalArray(int, [170, 45, 75, 90, 802, 24, 2, 66])
436+
expected_arr = [2, 24, 45, 66, 75, 90, 170, 802]
437+
out = radix_sort(arr)
438+
assert [out[i] for i in range(len(out))] == expected_arr
439+
440+
# Test partial sort with start/end
441+
arr = OneDimensionalArray(int, [170, 45, 75, 90, 802, 24, 2, 66])
442+
out = radix_sort(arr, start=2, end=5)
443+
expected_arr = [170, 45, 75, 90, 802, 24, 2, 66]
444+
assert [out[i] for i in range(len(out))] == expected_arr
445+
446+
# Test with None values
447+
arr = DynamicOneDimensionalArray(int, 0)
448+
arr.append(45)
449+
arr.append(None)
450+
arr.append(12)
451+
arr.append(None)
452+
arr.append(89)
453+
out = radix_sort(arr)
454+
assert out[0] == 12
455+
assert out[1] == 45
456+
assert out[2] == 89
457+
assert out[3] is None
458+
assert out[4] is None

0 commit comments

Comments
 (0)