|
1 | 1 | """ |
2 | | -This is a pure Python implementation of the merge sort algorithm. |
3 | | -
|
4 | | -For doctests run following command: |
5 | | -python -m doctest -v merge_sort.py |
6 | | -or |
7 | | -python3 -m doctest -v merge_sort.py |
8 | | -For manual testing run: |
9 | | -python merge_sort.py |
| 2 | +Optimized pure Python implementation of the merge sort algorithm. |
| 3 | +
|
| 4 | +Merge Sort is a divide-and-conquer algorithm that splits the input list into halves, |
| 5 | +recursively sorts them, and merges the sorted halves. |
| 6 | +
|
| 7 | +Source: https://en.wikipedia.org/wiki/Merge_sort |
10 | 8 | """ |
11 | 9 |
|
| 10 | +from __future__ import annotations |
12 | 11 |
|
13 | | -def merge_sort(collection: list) -> list: |
14 | | - """ |
15 | | - Sorts a list using the merge sort algorithm. |
| 12 | +from collections.abc import Sequence |
| 13 | +from typing import Any, Protocol, TypeVar |
| 14 | + |
| 15 | + |
| 16 | +class Comparable(Protocol): |
| 17 | + """Defines minimal comparison operations required for sorting.""" |
| 18 | + def __lt__(self, other: Any) -> bool: ... |
| 19 | + def __le__(self, other: Any) -> bool: ... |
16 | 20 |
|
17 | | - :param collection: A mutable ordered collection with comparable items. |
18 | | - :return: The same collection ordered in ascending order. |
19 | 21 |
|
20 | | - Time Complexity: O(n log n) |
21 | | - Space Complexity: O(n) |
| 22 | +T = TypeVar("T", bound=Comparable) |
| 23 | + |
| 24 | + |
| 25 | +def merge_sort(arr: Sequence[T]) -> list[T]: # noqa: UP047 |
| 26 | + """ |
| 27 | + Sort a sequence in ascending order using merge sort. |
| 28 | +
|
| 29 | + :param arr: Any sequence of comparable items. |
| 30 | + :return: A new sorted list. |
22 | 31 |
|
23 | | - Examples: |
24 | 32 | >>> merge_sort([0, 5, 3, 2, 2]) |
25 | 33 | [0, 2, 2, 3, 5] |
26 | 34 | >>> merge_sort([]) |
27 | 35 | [] |
28 | 36 | >>> merge_sort([-2, -5, -45]) |
29 | 37 | [-45, -5, -2] |
| 38 | + >>> merge_sort(["b", "a", "c"]) |
| 39 | + ['a', 'b', 'c'] |
| 40 | + >>> merge_sort((3, 1, 2)) |
| 41 | + [1, 2, 3] |
30 | 42 | """ |
| 43 | + n = len(arr) |
| 44 | + if n <= 1: |
| 45 | + return list(arr) |
31 | 46 |
|
32 | | - def merge(left: list, right: list) -> list: |
33 | | - """ |
34 | | - Merge two sorted lists into a single sorted list. |
| 47 | + mid = n // 2 |
| 48 | + left = merge_sort(arr[:mid]) |
| 49 | + right = merge_sort(arr[mid:]) |
| 50 | + return _merge(left, right) |
35 | 51 |
|
36 | | - :param left: Left collection |
37 | | - :param right: Right collection |
38 | | - :return: Merged result |
39 | | - """ |
40 | | - result = [] |
41 | | - while left and right: |
42 | | - result.append(left.pop(0) if left[0] <= right[0] else right.pop(0)) |
43 | | - result.extend(left) |
44 | | - result.extend(right) |
45 | | - return result |
46 | 52 |
|
47 | | - if len(collection) <= 1: |
48 | | - return collection |
49 | | - mid_index = len(collection) // 2 |
50 | | - return merge(merge_sort(collection[:mid_index]), merge_sort(collection[mid_index:])) |
| 53 | +def _merge(left: list[T], right: list[T]) -> list[T]: |
| 54 | + """Merge two sorted lists efficiently using index pointers.""" |
| 55 | + merged: list[T] = [] |
| 56 | + i = j = 0 |
| 57 | + while i < len(left) and j < len(right): |
| 58 | + if left[i] <= right[j]: |
| 59 | + merged.append(left[i]) |
| 60 | + i += 1 |
| 61 | + else: |
| 62 | + merged.append(right[j]) |
| 63 | + j += 1 |
| 64 | + merged.extend(left[i:]) |
| 65 | + merged.extend(right[j:]) |
| 66 | + return merged |
51 | 67 |
|
52 | 68 |
|
53 | 69 | if __name__ == "__main__": |
54 | 70 | import doctest |
55 | 71 |
|
56 | | - doctest.testmod() |
| 72 | + doctest.testmod(verbose=True) |
57 | 73 |
|
58 | 74 | try: |
59 | | - user_input = input("Enter numbers separated by a comma:\n").strip() |
60 | | - unsorted = [int(item) for item in user_input.split(",")] |
61 | | - sorted_list = merge_sort(unsorted) |
62 | | - print(*sorted_list, sep=",") |
| 75 | + user_input = input("Enter numbers separated by commas:\n").strip() |
| 76 | + numbers = [int(x) for x in user_input.split(",") if x.strip()] |
| 77 | + print("Sorted:", merge_sort(numbers)) |
63 | 78 | except ValueError: |
64 | | - print("Invalid input. Please enter valid integers separated by commas.") |
| 79 | + print("Invalid input. Please enter only comma-separated integers.") |
0 commit comments