From f99c42f091536c6b1c3d2d0b2d60224fba8c4f73 Mon Sep 17 00:00:00 2001 From: arvinder004 Date: Wed, 19 Mar 2025 21:18:16 +0530 Subject: [PATCH 1/7] added shell sort with tests and documentation --- AUTHORS | 1 + .../linear_data_structures/algorithms.py | 75 +++++++++++++++++++ .../tests/test_algorithms.py | 22 ++++++ 3 files changed, 98 insertions(+) diff --git a/AUTHORS b/AUTHORS index 943bf804d..8b5220bb7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,3 +11,4 @@ Pratik Goyal Jay Thorat Rajveer Singh Bharadwaj Kishan Ved +Arvinder Singh Dhoul \ No newline at end of file diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 792bce855..4f4316206 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1850,3 +1850,78 @@ def partition(array, lower, upper): intro_sort(array, start=p+1, end=upper, maxdepth=maxdepth-1, ins_threshold=ins_threshold) return array + +def shell_sort(array, **kwargs): + """ + Implements shell sort algorithm. + + Parameters + ========== + + array: Array + The array which is to be sorted. + start: int + The starting index of the portion + which is to be sorted. + Optional, by default 0 + end: int + The ending index of the portion which + is to be sorted. + Optional, by default the index + of the last position filled. + comp: lambda/function + The comparator which is to be used + for sorting. If the function returns + False then only swapping is performed. + Optional, by default, less than or + equal to is used for comparing two + values. + backend: pydatastructs.Backend + The backend to be used. + Optional, by default, the best available + backend is used. + + Returns + ======= + + output: Array + The sorted array. + + Examples + ======== + + >>> from pydatastructs.linear_data_structures.algorithms import OneDimensionalArray, shell_sort + >>> arr = OneDimensionalArray(int, [3, 2, 1]) + >>> out = shell_sort(arr) + >>> str(out) + '[1, 2, 3]' + >>> out = shell_sort(arr, comp=lambda u, v: u > v) + >>> str(out) + '[3, 2, 1]' + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Shellsort + """ + backend = kwargs.pop("backend", Backend.PYTHON) + if backend == Backend.CPP: + return _algorithms.shell_sort(array, **kwargs) + start = kwargs.get('start', 0) + end = kwargs.get('end', len(array) - 1) + comp = kwargs.get('comp', lambda u, v: u <= v) + n = end - start + 1 + gap = n // 2 + while gap > 0: + for i in range(start + gap, end + 1): + temp = array[i] + j = i + while j >= start + gap and not _comp(array[j - gap], temp, comp): + array[j] = array[j - gap] + j -= gap + array[j] = temp + gap //= 2 + if _check_type(array, (DynamicArray, _arrays.DynamicOneDimensionalArray)): + array._modify(True) + + return array diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index 46609544b..8a1391e83 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -7,6 +7,7 @@ prev_permutation, bubble_sort, linear_search, binary_search, jump_search, selection_sort, insertion_sort, intro_sort, Backend) +from pydatastructs.linear_data_structures.algorithms import shell_sort from pydatastructs.utils.raises_util import raises import random @@ -414,3 +415,24 @@ def test_binary_search(): def test_jump_search(): _test_common_search(jump_search) _test_common_search(jump_search, backend=Backend.CPP) + +def test_shell_sort(): + assert shell_sort([]) == [] + + assert shell_sort([42]) == [42] + + input_data = [1, 2, 3, 4, 5] + expected = [1, 2, 3, 4, 5] + assert shell_sort(input_data) == expected + + input_data = [5, 4, 3, 2, 1] + expected = [1, 2, 3, 4, 5] + assert shell_sort(input_data) == expected + + input_data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] + expected = [1, 1, 2, 3, 3, 4, 5, 5, 6, 9] + assert shell_sort(input_data) == expected + + input_data = [-5, 3, -10, 7, 0, -2] + expected = [-10, -5, -2, 0, 3, 7] + assert shell_sort(input_data) == expected From 7c7d2090b0dbe7087e17fbecf5e28abda26ec8cd Mon Sep 17 00:00:00 2001 From: arvinder004 Date: Thu, 20 Mar 2025 00:26:55 +0530 Subject: [PATCH 2/7] added featur: radix sort --- .../linear_data_structures/algorithms.py | 96 +++++++++++++++++++ .../tests/test_algorithms.py | 25 ++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 4f4316206..e91a1ece1 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1925,3 +1925,99 @@ def shell_sort(array, **kwargs): array._modify(True) return array + +def radix_sort(array, **kwargs): + """ + Implements radix sort algorithm for non-negative integers. + + Parameters + ========== + + array: Array + The array which is to be sorted. Must contain non-negative integers. + start: int + The starting index of the portion + which is to be sorted. + Optional, by default 0 + end: int + The ending index of the portion which + is to be sorted. + Optional, by default the index + of the last position filled. + comp: lambda/function + The comparator which is to be used + for sorting. If the function returns + False then only swapping is performed. + Optional, by default, less than or + equal to is used for comparing two + values. + backend: pydatastructs.Backend + The backend to be used. + Optional, by default, the best available + backend is used. + + Returns + ======= + + output: Array + The sorted array. + + Examples + ======== + + >>> from pydatastructs.linear_data_structures.algorithms import OneDimensionalArray, radix_sort + >>> arr = OneDimensionalArray(int, [170, 45, 75, 90, 802, 24, 2, 66]) + >>> out = radix_sort(arr) + >>> str(out) + '[2, 24, 45, 66, 75, 90, 170, 802]' + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Radix_sort + """ + backend = kwargs.pop("backend", Backend.PYTHON) + if backend == Backend.CPP: + return _algorithms.radix_sort(array, **kwargs) + start = int(kwargs.get('start', 0)) + end = int(kwargs.get('end', len(array) - 1)) + + if start >= end: + return array + + n = end - start + 1 + if n <= 0: + return array + + max_val = array[start] + for i in range(start + 1, end + 1): + if array[i] > max_val: + max_val = array[i] + if max_val < 0: + raise ValueError("Radix sort requires non-negative integers") + + exp = 1 + while max_val // exp > 0: + count = [0] * 10 + output = [0] * n + for i in range(start, end + 1): + digit = (array[i] // exp) % 10 + count[digit] += 1 + + for i in range(1, 10): + count[i] += count[i - 1] + + for i in range(end, start - 1, -1): + digit = (array[i] // exp) % 10 + count[digit] -= 1 + output[count[digit]] = array[i] + + for i in range(n): + array[start + i] = output[i] + + exp *= 10 + + if _check_type(array, (DynamicArray, _arrays.DynamicOneDimensionalArray)): + array._modify(True) + + return array diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index 8a1391e83..f279e5d38 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -7,9 +7,9 @@ prev_permutation, bubble_sort, linear_search, binary_search, jump_search, selection_sort, insertion_sort, intro_sort, Backend) -from pydatastructs.linear_data_structures.algorithms import shell_sort +from pydatastructs.linear_data_structures.algorithms import shell_sort, radix_sort from pydatastructs.utils.raises_util import raises -import random +import random, pytest def _test_common_sort(sort, *args, **kwargs): random.seed(1000) @@ -436,3 +436,24 @@ def test_shell_sort(): input_data = [-5, 3, -10, 7, 0, -2] expected = [-10, -5, -2, 0, 3, 7] assert shell_sort(input_data) == expected + +def test_radix_sort(): + assert radix_sort([]) == [] + + assert radix_sort([42]) == [42] + + input_data = [1, 2, 3, 4, 5] + expected = [1, 2, 3, 4, 5] + assert radix_sort(input_data) == expected + + input_data = [5, 4, 3, 2, 1] + expected = [1, 2, 3, 4, 5] + assert radix_sort(input_data) == expected + + input_data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] + expected = [1, 1, 2, 3, 3, 4, 5, 5, 6, 9] + assert radix_sort(input_data) == expected + + input_data = [1000, 10, 100, 1, 10000] + expected = [1, 10, 100, 1000, 10000] + assert radix_sort(input_data) == expected From 99cd58071649db2c57b8f5820c3667f4d9d7bbe3 Mon Sep 17 00:00:00 2001 From: arvinder004 Date: Thu, 20 Mar 2025 11:17:39 +0530 Subject: [PATCH 3/7] updated docs and imports related to shell_sort and radix_sort --- .../linear_data_structures/algorithms.rst | 6 +++++- pydatastructs/linear_data_structures/__init__.py | 4 +++- pydatastructs/linear_data_structures/algorithms.py | 10 +++------- .../linear_data_structures/tests/test_algorithms.py | 3 +-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/source/pydatastructs/linear_data_structures/algorithms.rst b/docs/source/pydatastructs/linear_data_structures/algorithms.rst index 7ab521cfd..8cc871986 100644 --- a/docs/source/pydatastructs/linear_data_structures/algorithms.rst +++ b/docs/source/pydatastructs/linear_data_structures/algorithms.rst @@ -45,4 +45,8 @@ Algorithms .. autofunction:: pydatastructs.jump_search -.. autofunction:: pydatastructs.intro_sort \ No newline at end of file +.. autofunction:: pydatastructs.intro_sort + +.. autofunction:: pydatastructs.shell_sort + +.. autofunction:: pydatastructs.radix_sort \ No newline at end of file diff --git a/pydatastructs/linear_data_structures/__init__.py b/pydatastructs/linear_data_structures/__init__.py index 057adc169..de247b88e 100644 --- a/pydatastructs/linear_data_structures/__init__.py +++ b/pydatastructs/linear_data_structures/__init__.py @@ -47,6 +47,8 @@ jump_search, selection_sort, insertion_sort, - intro_sort + intro_sort, + shell_sort, + radix_sort ) __all__.extend(algorithms.__all__) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index e91a1ece1..9880cf1ad 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -30,7 +30,9 @@ 'jump_search', 'selection_sort', 'insertion_sort', - 'intro_sort' + 'intro_sort', + 'shell_sort', + 'radix_sort' ] def _merge(array, sl, el, sr, er, end, comp): @@ -1904,9 +1906,6 @@ def shell_sort(array, **kwargs): .. [1] https://en.wikipedia.org/wiki/Shellsort """ - backend = kwargs.pop("backend", Backend.PYTHON) - if backend == Backend.CPP: - return _algorithms.shell_sort(array, **kwargs) start = kwargs.get('start', 0) end = kwargs.get('end', len(array) - 1) comp = kwargs.get('comp', lambda u, v: u <= v) @@ -1976,9 +1975,6 @@ def radix_sort(array, **kwargs): .. [1] https://en.wikipedia.org/wiki/Radix_sort """ - backend = kwargs.pop("backend", Backend.PYTHON) - if backend == Backend.CPP: - return _algorithms.radix_sort(array, **kwargs) start = int(kwargs.get('start', 0)) end = int(kwargs.get('end', len(array) - 1)) diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index f279e5d38..0f1594021 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -5,9 +5,8 @@ cocktail_shaker_sort, quick_sort, longest_common_subsequence, is_ordered, upper_bound, lower_bound, longest_increasing_subsequence, next_permutation, prev_permutation, bubble_sort, linear_search, binary_search, jump_search, - selection_sort, insertion_sort, intro_sort, Backend) + selection_sort, insertion_sort, intro_sort, shell_sort, radix_sort, Backend) -from pydatastructs.linear_data_structures.algorithms import shell_sort, radix_sort from pydatastructs.utils.raises_util import raises import random, pytest From 1e724099d363cf6d2ab1858dc092c9c44c5f658e Mon Sep 17 00:00:00 2001 From: arvinder004 Date: Thu, 20 Mar 2025 11:55:24 +0530 Subject: [PATCH 4/7] updated imports --- pydatastructs/linear_data_structures/tests/test_algorithms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index 0f1594021..b9ca954a5 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -8,7 +8,7 @@ selection_sort, insertion_sort, intro_sort, shell_sort, radix_sort, Backend) from pydatastructs.utils.raises_util import raises -import random, pytest +import random def _test_common_sort(sort, *args, **kwargs): random.seed(1000) From 0e11cf4818624ba20ccd68a8ee5baf413d9c25f2 Mon Sep 17 00:00:00 2001 From: arvinder004 Date: Thu, 20 Mar 2025 12:36:49 +0530 Subject: [PATCH 5/7] resolved test errors for radix sort and shell sort --- .../linear_data_structures/algorithms.py | 37 ++++++++--------- .../tests/test_algorithms.py | 40 +------------------ 2 files changed, 19 insertions(+), 58 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 9880cf1ad..91a362b6b 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1853,7 +1853,7 @@ def partition(array, lower, upper): return array -def shell_sort(array, **kwargs): +def shell_sort(array, *args, **kwargs): """ Implements shell sort algorithm. @@ -1906,9 +1906,10 @@ def shell_sort(array, **kwargs): .. [1] https://en.wikipedia.org/wiki/Shellsort """ - start = kwargs.get('start', 0) - end = kwargs.get('end', len(array) - 1) + start = int(kwargs.get('start', 0)) + end = int(kwargs.get('end', len(array) - 1)) comp = kwargs.get('comp', lambda u, v: u <= v) + n = end - start + 1 gap = n // 2 while gap > 0: @@ -1920,12 +1921,13 @@ def shell_sort(array, **kwargs): j -= gap array[j] = temp gap //= 2 + if _check_type(array, (DynamicArray, _arrays.DynamicOneDimensionalArray)): array._modify(True) return array -def radix_sort(array, **kwargs): +def radix_sort(array, *args, **kwargs): """ Implements radix sort algorithm for non-negative integers. @@ -1977,36 +1979,31 @@ def radix_sort(array, **kwargs): """ start = int(kwargs.get('start', 0)) end = int(kwargs.get('end', len(array) - 1)) - - if start >= end: - return array + comp = kwargs.get('comp', lambda u, v: u <= v) n = end - start + 1 - if n <= 0: - return array - max_val = array[start] for i in range(start + 1, end + 1): - if array[i] > max_val: + if array[i] is not None and array[i] > max_val: max_val = array[i] - if max_val < 0: - raise ValueError("Radix sort requires non-negative integers") - exp = 1 while max_val // exp > 0: count = [0] * 10 - output = [0] * n + output = [None] * n + for i in range(start, end + 1): - digit = (array[i] // exp) % 10 - count[digit] += 1 + if array[i] is not None: + digit = (array[i] // exp) % 10 + count[digit] += 1 for i in range(1, 10): count[i] += count[i - 1] for i in range(end, start - 1, -1): - digit = (array[i] // exp) % 10 - count[digit] -= 1 - output[count[digit]] = array[i] + if array[i] is not None: + digit = (array[i] // exp) % 10 + count[digit] -= 1 + output[count[digit]] = array[i] for i in range(n): array[start + i] = output[i] diff --git a/pydatastructs/linear_data_structures/tests/test_algorithms.py b/pydatastructs/linear_data_structures/tests/test_algorithms.py index b9ca954a5..dc6336b48 100644 --- a/pydatastructs/linear_data_structures/tests/test_algorithms.py +++ b/pydatastructs/linear_data_structures/tests/test_algorithms.py @@ -416,43 +416,7 @@ def test_jump_search(): _test_common_search(jump_search, backend=Backend.CPP) def test_shell_sort(): - assert shell_sort([]) == [] - - assert shell_sort([42]) == [42] - - input_data = [1, 2, 3, 4, 5] - expected = [1, 2, 3, 4, 5] - assert shell_sort(input_data) == expected - - input_data = [5, 4, 3, 2, 1] - expected = [1, 2, 3, 4, 5] - assert shell_sort(input_data) == expected - - input_data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] - expected = [1, 1, 2, 3, 3, 4, 5, 5, 6, 9] - assert shell_sort(input_data) == expected - - input_data = [-5, 3, -10, 7, 0, -2] - expected = [-10, -5, -2, 0, 3, 7] - assert shell_sort(input_data) == expected + _test_common_sort(shell_sort) def test_radix_sort(): - assert radix_sort([]) == [] - - assert radix_sort([42]) == [42] - - input_data = [1, 2, 3, 4, 5] - expected = [1, 2, 3, 4, 5] - assert radix_sort(input_data) == expected - - input_data = [5, 4, 3, 2, 1] - expected = [1, 2, 3, 4, 5] - assert radix_sort(input_data) == expected - - input_data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] - expected = [1, 1, 2, 3, 3, 4, 5, 5, 6, 9] - assert radix_sort(input_data) == expected - - input_data = [1000, 10, 100, 1, 10000] - expected = [1, 10, 100, 1000, 10000] - assert radix_sort(input_data) == expected + _test_common_sort(radix_sort) From 0347240780994bf138504f0c189e42cc9f704019 Mon Sep 17 00:00:00 2001 From: arvinder004 Date: Thu, 20 Mar 2025 23:00:52 +0530 Subject: [PATCH 6/7] commit --- pydatastructs/linear_data_structures/algorithms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 91a362b6b..798ff3843 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1979,7 +1979,6 @@ def radix_sort(array, *args, **kwargs): """ start = int(kwargs.get('start', 0)) end = int(kwargs.get('end', len(array) - 1)) - comp = kwargs.get('comp', lambda u, v: u <= v) n = end - start + 1 max_val = array[start] From 9248441e3da0ac30a9ccb0aa0d314bf38e02e858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A8=97=E0=A8=97=E0=A8=A8=E0=A8=A6=E0=A9=80=E0=A8=AA=20?= =?UTF-8?q?=E0=A8=B8=E0=A8=BF=E0=A9=B0=E0=A8=98=20=28Gagandeep=20Singh=29?= Date: Thu, 27 Mar 2025 22:44:10 +0530 Subject: [PATCH 7/7] Update pydatastructs/linear_data_structures/algorithms.py --- pydatastructs/linear_data_structures/algorithms.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pydatastructs/linear_data_structures/algorithms.py b/pydatastructs/linear_data_structures/algorithms.py index 798ff3843..8b7295833 100644 --- a/pydatastructs/linear_data_structures/algorithms.py +++ b/pydatastructs/linear_data_structures/algorithms.py @@ -1945,13 +1945,6 @@ def radix_sort(array, *args, **kwargs): is to be sorted. Optional, by default the index of the last position filled. - comp: lambda/function - The comparator which is to be used - for sorting. If the function returns - False then only swapping is performed. - Optional, by default, less than or - equal to is used for comparing two - values. backend: pydatastructs.Backend The backend to be used. Optional, by default, the best available