diff --git a/pyproject.toml b/pyproject.toml index a308fd9..7bc7add 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,3 +73,7 @@ docstring-code-format = true # This only has an effect when the `docstring-code-format` setting is # enabled. docstring-code-line-length = "dynamic" + +[tool.pytest.ini_options] +pythonpath = "." +testpaths = ["tests"] diff --git a/src/bubble_sort.py b/src/bubble_sort.py new file mode 100644 index 0000000..d09c5ef --- /dev/null +++ b/src/bubble_sort.py @@ -0,0 +1,14 @@ +def bubble_sort(arr: list) -> list: + arr = arr[:] + for i in range(len(arr)): + swapped = False + + for k in range(len(arr) - i - 1): + if arr[k] > arr[k + 1]: + arr[k], arr[k + 1] = arr[k + 1], arr[k] + swapped = True + + if not swapped: + break + + return arr diff --git a/src/heap_sort.py b/src/heap_sort.py new file mode 100644 index 0000000..d2560ab --- /dev/null +++ b/src/heap_sort.py @@ -0,0 +1,31 @@ +def heapify(arr: list, n: int, i: int) -> None: + largest = i + left = 2 * i + 1 + right = 2 * i + 2 + + if left < n and arr[left] > arr[largest]: + largest = left + + if right < n and arr[right] > arr[largest]: + largest = right + + if largest != i: + arr[i], arr[largest] = arr[largest], arr[i] + heapify(arr, n, largest) + + +def heap_sort(arr: list) -> list: + arr = arr[:] + n = len(arr) + + if n < 2: + return arr + + for i in range(n // 2 - 1, -1, -1): + heapify(arr, n, i) + + for i in range(n - 1, 0, -1): + arr[0], arr[i] = arr[i], arr[0] + heapify(arr, i, 0) + + return arr diff --git a/src/merge_sort.py b/src/merge_sort.py new file mode 100644 index 0000000..7b6d087 --- /dev/null +++ b/src/merge_sort.py @@ -0,0 +1,30 @@ +def merge_sort(arr: list) -> list: + if len(arr) < 2: + return arr + + mid = len(arr) // 2 + left = arr[:mid] + right = arr[mid:] + + left = merge_sort(left) + right = merge_sort(right) + + return merge(left, right) + + +def merge(left: list, right: list) -> list: + arr = [] + i = o = 0 + + while i < len(left) and o < len(right): + if left[i] <= right[o]: + arr.append(left[i]) + i += 1 + else: + arr.append(right[o]) + o += 1 + + arr.extend(left[i:]) + arr.extend(right[o:]) + + return arr diff --git a/src/quick_sort.py b/src/quick_sort.py new file mode 100644 index 0000000..1487712 --- /dev/null +++ b/src/quick_sort.py @@ -0,0 +1,41 @@ +import random + + +def quick_sort(arr: list) -> list: + if not isinstance(arr, list): + raise TypeError("Передан не список") + + if len(arr) < 2: + return arr + + arr = arr[:] + + def _quick_sort(arr: list, left: int, right: int) -> None: + + if left >= right: + return None + + random_index = random.randint(left, right) + arr[random_index], arr[left] = arr[left], arr[random_index] + + i = left + new_left, new_right = left, right + pivot = arr[left] + + while i <= new_right: + if arr[i] < pivot: + arr[new_left], arr[i] = arr[i], arr[new_left] + new_left += 1 + i += 1 + elif arr[i] > pivot: + arr[i], arr[new_right] = arr[new_right], arr[i] + new_right -= 1 + else: + i += 1 + + _quick_sort(arr, left, new_left - 1) + _quick_sort(arr, new_right + 1, right) + + _quick_sort(arr, 0, len(arr) - 1) + + return arr diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..158f7eb --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ +import random + +import pytest + + +@pytest.fixture +def random_list(): + list_len = random.randint(100, 2000) + random_list = [random.randint(-(10**11), 10**11) for _ in range(list_len)] + return random_list diff --git a/tests/test_parametrized.py b/tests/test_parametrized.py new file mode 100644 index 0000000..da9586b --- /dev/null +++ b/tests/test_parametrized.py @@ -0,0 +1,35 @@ +import pytest + +from src.bubble_sort import bubble_sort +from src.heap_sort import heap_sort +from src.merge_sort import merge_sort +from src.quick_sort import quick_sort + + +@pytest.mark.parametrize( + ["arr", "expected"], + [ + ([1, 5, 3, 2, 4], [1, 2, 3, 4, 5]), + ([7, 6, 23423524], [6, 7, 23423524]), + ([], []), + ([5], [5]), + ([5, 4], [4, 5]), + ([5, 4, 3, 2, 1], [1, 2, 3, 4, 5]), + ([3, 2, 1, 3, 3, 3, 3, 3, 3], [1, 2, 3, 3, 3, 3, 3, 3, 3]), + ([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]), + ([0.11, 0.43, 43.21, -321.54, -11.07], [-321.54, -11.07, 0.11, 0.43, 43.21]), + ([2, 2, 2, 2], [2, 2, 2, 2]), + ([0, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 0, 1, 1, 1, 1]), + ([12, -100, 47, -123, -5, 1, 0, -3], [-123, -100, -5, -3, 0, 1, 12, 47]), + ], +) +def test_sort_parametrized(arr, expected): + heap_sorted = heap_sort(arr) + quick_sorted = quick_sort(arr) + merge_sorted = merge_sort(arr) + bubble_sorted = bubble_sort(arr) + + assert heap_sorted == expected + assert quick_sorted == expected + assert merge_sorted == expected + assert bubble_sorted == expected diff --git a/tests/test_random.py b/tests/test_random.py new file mode 100644 index 0000000..7080754 --- /dev/null +++ b/tests/test_random.py @@ -0,0 +1,22 @@ +import pytest +from conftest import random_list # noqa: F401 + +from src.bubble_sort import bubble_sort +from src.heap_sort import heap_sort +from src.merge_sort import merge_sort +from src.quick_sort import quick_sort + + +@pytest.mark.repeat(100) +def test_sort_random(random_list): # noqa: F811 + expected = sorted(random_list) + + heap_sorted = heap_sort(random_list) + quick_sorted = quick_sort(random_list) + merge_sorted = merge_sort(random_list) + bubble_sorted = bubble_sort(random_list) + + assert heap_sorted == expected + assert quick_sorted == expected + assert merge_sorted == expected + assert bubble_sorted == expected