From e094f88cb61bb170d289ed9260d79cd9737a1eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D1=80=D1=8C=D1=8F=20=D0=A2=D0=BE=D1=80=D0=B3?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0?= Date: Sun, 7 Dec 2025 22:18:10 +0300 Subject: [PATCH 1/2] Added implementations of heap, merge, quich sorts. Built tests for heap sort. --- pyproject.toml | 4 ++ src/tests_pytest_6/heap_sort.py | 27 +++++++ src/tests_pytest_6/merge_sort.py | 30 ++++++++ src/tests_pytest_6/quick_sort.py | 65 +++++++++++++++++ tests/test_heap_sort.py | 118 +++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 src/tests_pytest_6/heap_sort.py create mode 100644 src/tests_pytest_6/merge_sort.py create mode 100644 src/tests_pytest_6/quick_sort.py create mode 100644 tests/test_heap_sort.py diff --git a/pyproject.toml b/pyproject.toml index d268a5e..e88c832 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,3 +16,7 @@ target-version = "py312" "RET", # Хорошие практики возврата "SIM", # Общие правила упрощения ] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["src"] diff --git a/src/tests_pytest_6/heap_sort.py b/src/tests_pytest_6/heap_sort.py new file mode 100644 index 0000000..a229154 --- /dev/null +++ b/src/tests_pytest_6/heap_sort.py @@ -0,0 +1,27 @@ +def heapify(arr, n, i): + largest = i + left = 2 * i + 1 + right = 2 * i + 2 + + if left < n and arr[i] < arr[left]: + largest = left + + if right < n and arr[largest] < arr[right]: + largest = right + + if largest != i: + arr[i], arr[largest] = arr[largest], arr[i] + heapify(arr, n, largest) + + +def heap_sort(arr): + n = len(arr) + + for i in range(n // 2 - 1, -1, -1): + heapify(arr, n, i) + + for i in range(n - 1, 0, -1): + arr[i], arr[0] = arr[0], arr[i] + + heapify(arr, i, 0) + return arr diff --git a/src/tests_pytest_6/merge_sort.py b/src/tests_pytest_6/merge_sort.py new file mode 100644 index 0000000..aad5ee2 --- /dev/null +++ b/src/tests_pytest_6/merge_sort.py @@ -0,0 +1,30 @@ +def merge_sort(arr): + if len(arr) > 1: + mid = len(arr) // 2 + left = arr[:mid] + right = arr[mid:] + + merge_sort(left) + merge_sort(right) + + i = j = k = 0 + + while i < len(left) and j < len(right): + if left[i] < right[j]: + arr[k] = left[i] + i += 1 + else: + arr[k] = right[j] + j += 1 + k += 1 + + while i < len(left): + arr[k] = left[i] + i += 1 + k += 1 + + while j < len(right): + arr[k] = right[j] + j += 1 + k += 1 + return arr diff --git a/src/tests_pytest_6/quick_sort.py b/src/tests_pytest_6/quick_sort.py new file mode 100644 index 0000000..1ebd246 --- /dev/null +++ b/src/tests_pytest_6/quick_sort.py @@ -0,0 +1,65 @@ +def partition(array, start, end): + pivot = array[start] + low = start + 1 + high = end + + while True: + while low <= high and array[high] >= pivot: + high = high - 1 + + while low <= high and array[low] <= pivot: + low = low + 1 + + if low <= high: + array[low], array[high] = array[high], array[low] + else: + break + + array[start], array[high] = array[high], array[start] + + return high + + +def quick_sort(array, start=0, end=None): + if end is None: + end = len(array) - 1 + + if start >= end: + return array + + p = partition(array, start, end) + quick_sort(array, start, p - 1) + quick_sort(array, p + 1, end) + return array + + +def merge_sort(arr): + if len(arr) > 1: + mid = len(arr) // 2 + left = arr[:mid] + right = arr[mid:] + + merge_sort(left) + merge_sort(right) + + i = j = k = 0 + + while i < len(left) and j < len(right): + if left[i] < right[j]: + arr[k] = left[i] + i += 1 + else: + arr[k] = right[j] + j += 1 + k += 1 + + while i < len(left): + arr[k] = left[i] + i += 1 + k += 1 + + while j < len(right): + arr[k] = right[j] + j += 1 + k += 1 + return arr diff --git a/tests/test_heap_sort.py b/tests/test_heap_sort.py new file mode 100644 index 0000000..ee3fdc3 --- /dev/null +++ b/tests/test_heap_sort.py @@ -0,0 +1,118 @@ +import random + +import pytest +from tests_pytest_6.heap_sort import heap_sort, heapify +from tests_pytest_6.merge_sort import merge_sort +from tests_pytest_6.quick_sort import quick_sort + +# unit тесты + + +def test_heapify_work(): + """Тест функции heapify на корректность""" + arr = [1, 3, 2] + heapify(arr, 3, 0) + assert arr == [3, 1, 2] + + +def test_duplicate_elements(): + """Тест с дубликатами""" + assert heap_sort([3, 1, 2, 3, 1]) == [1, 1, 2, 3, 3] + + +def test_negative_numbers(): + """Тест с отрицательными числами""" + assert heap_sort([-5, 3, -1, 0, 2]) == [-5, -1, 0, 2, 3] + + +# крайние случаи + + +def test_empty_list(): + """Тест пустого списка""" + assert heap_sort([]) == [] + + +def test_single_element(): + """Тест одного элемента""" + assert heap_sort([5]) == [5] + + +def test_sorted_list(): + """Тест уже отсортированного списка""" + assert heap_sort([1, 2, 3, 4, 5]) == [1, 2, 3, 4, 5] + + +def test_reverse_sorted(): + """Тест обратно отсортированного списка""" + assert heap_sort([5, 4, 3, 2, 1]) == [1, 2, 3, 4, 5] + + +def test_large_list(): + """Тест большого списка""" + lst = list(range(1000, 0, -1)) + expected = list(range(1, 1001)) + assert heap_sort(lst) == expected + + +# параметризованный тест + + +@pytest.mark.parametrize( + "arr, expected", + [([], []), ([5], [5]), ([3, 1], [1, 3]), ([3, 1, 5, 7], [1, 3, 5, 7])], +) +def test_heap_sort_main(arr, expected): + assert heap_sort(arr) == expected + + +# property-based тесты + + +def test_property_idempotence(): + """Повторная сортировка не меняет результат""" + for _ in range(100): + lst = [random.randint(-1000, 1000) for _ in range(random.randint(0, 100))] + sorted_once = heap_sort(lst.copy()) + sorted_twice = heap_sort(sorted_once.copy()) + assert sorted_once == sorted_twice + + +def test_property_length_preservation(): + """Длина списка сохраняется""" + for _ in range(100): + lst = [random.randint(-1000, 1000) for _ in range(random.randint(0, 100))] + assert len(heap_sort(lst)) == len(lst) + + +def test_property_sorted_order(): + """Результат должен быть отсортирован""" + for _ in range(100): + lst = [random.randint(-1000, 1000) for _ in range(random.randint(1, 100))] + sorted_lst = heap_sort(lst) + for i in range(1, len(sorted_lst)): + assert sorted_lst[i - 1] <= sorted_lst[i] + + +def test_against_builtin_sort(): + """Сравнение со встроенной сортировкой Python""" + for _ in range(100): + lst = [random.randint(-1000, 1000) for _ in range(random.randint(0, 100))] + assert heap_sort(lst.copy()) == sorted(lst) + + +# Сравнение с другими сортировками + + +def test_against_quick_sort(): + """Сравнение с quick_sort""" + for _ in range(50): + lst = [random.randint(-100, 100) for _ in range(random.randint(0, 50))] + assert heap_sort(lst.copy()) == quick_sort(lst.copy()) + + +def test_against_merge_sort(): + """Сравнение с merge_sort""" + for _ in range(50): + lst = [random.randint(-100, 100) for _ in range(random.randint(0, 50))] + assert heap_sort(lst.copy()) == merge_sort(lst.copy()) From b2d68bee5b46a5a3bf393ce83ad72983428dd8e2 Mon Sep 17 00:00:00 2001 From: Daria Date: Mon, 8 Dec 2025 19:49:49 +0300 Subject: [PATCH 2/2] Update quick_sort.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Забыла изначально удалить функцию merge_sort --- src/tests_pytest_6/quick_sort.py | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/tests_pytest_6/quick_sort.py b/src/tests_pytest_6/quick_sort.py index 1ebd246..63fb9e0 100644 --- a/src/tests_pytest_6/quick_sort.py +++ b/src/tests_pytest_6/quick_sort.py @@ -31,35 +31,3 @@ def quick_sort(array, start=0, end=None): quick_sort(array, start, p - 1) quick_sort(array, p + 1, end) return array - - -def merge_sort(arr): - if len(arr) > 1: - mid = len(arr) // 2 - left = arr[:mid] - right = arr[mid:] - - merge_sort(left) - merge_sort(right) - - i = j = k = 0 - - while i < len(left) and j < len(right): - if left[i] < right[j]: - arr[k] = left[i] - i += 1 - else: - arr[k] = right[j] - j += 1 - k += 1 - - while i < len(left): - arr[k] = left[i] - i += 1 - k += 1 - - while j < len(right): - arr[k] = right[j] - j += 1 - k += 1 - return arr