Skip to content

Commit 15479f2

Browse files
xiao115255claude
andcommitted
sorts: type recursive_quick_sort for any comparable items
Rename the function from quick_sort to recursive_quick_sort so its parametrize id in tests/test_sorts.py is unique (it would otherwise collide with sorts/quick_sort.py:quick_sort). Constrain the items to the existing Comparable Protocol with PEP 695 [T: Comparable] and list[T] -> list[T], matching the merged sibling sorts/quick_sort.py and sorts/bubble_sort.py patterns. Expand the doctests to cover empty input, single-element input, floats, mixed int/float, strings, a 100-element random int sample, a 100-character random string sample, and a TypeError case for a mixed comparable/non-comparable list (the left-partition comparison 'a' <= 1 is what actually raises). Register the sort in tests/test_sorts.py so it joins the shared test_sort_matches_builtin battery (all 11 comparison-sort cases) and the test_sort_rejects_non_comparable_items battery. Part of #15234 Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 0a72d14 commit 15479f2

2 files changed

Lines changed: 97 additions & 14 deletions

File tree

‎sorts/recursive_quick_sort.py‎

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,102 @@
1-
def quick_sort(data: list) -> list:
2-
"""
3-
>>> for data in ([2, 1, 0], [2.2, 1.1, 0], "quick_sort"):
4-
... quick_sort(data) == sorted(data)
1+
"""
2+
A pure Python implementation of the recursive quick sort algorithm
3+
4+
This variant of quicksort picks the first element of the collection as the
5+
pivot and recursively sorts the two sub-collections that fall on either
6+
side of that pivot. It returns a new list with the same items in
7+
non-decreasing order; the input list is never modified (for inputs of
8+
length less than two the very same list object is returned as-is).
9+
10+
For doctests run following command:
11+
python3 -m doctest -v recursive_quick_sort.py
12+
13+
For manual testing run:
14+
python3 recursive_quick_sort.py
15+
"""
16+
17+
from typing import Any, Protocol, TypeVar
18+
19+
20+
class Comparable(Protocol):
21+
def __lt__(self, other: Any, /) -> bool: ...
22+
23+
24+
T = TypeVar("T", bound=Comparable)
25+
26+
27+
def recursive_quick_sort[T: Comparable](collection: list[T]) -> list[T]:
28+
"""A pure Python implementation of the recursive quick sort algorithm.
29+
30+
The first element of ``collection`` is used as the pivot: every
31+
remaining item that is less than or equal to the pivot goes into
32+
the left sub-collection, every greater item into the right one, and
33+
the two sub-collections are then sorted recursively.
34+
35+
Complexity Analysis:
36+
Time Complexity:
37+
- Best Case: O(n log n) when the pivot splits evenly
38+
- Average Case: O(n log n)
39+
- Worst Case: O(n^2) when the first element is always an
40+
extreme of the remaining items (e.g. an already sorted or
41+
reverse sorted collection)
42+
Space Complexity:
43+
- O(n) for the sub-collections built at every recursion level
44+
(the algorithm does not mutate the input)
45+
46+
:param collection: some mutable ordered collection with mutually
47+
comparable items inside
48+
:return: a list with the same items ordered in ascending order
49+
50+
Examples:
51+
>>> recursive_quick_sort([0, 5, 3, 2, 2])
52+
[0, 2, 2, 3, 5]
53+
>>> recursive_quick_sort([])
54+
[]
55+
>>> recursive_quick_sort([5])
56+
[5]
57+
>>> recursive_quick_sort([-2, 5, 0, -45])
58+
[-45, -2, 0, 5]
59+
>>> recursive_quick_sort([2, 1, 0]) == sorted([2, 1, 0])
560
True
61+
>>> recursive_quick_sort([2.2, 1.1, 0.0]) == sorted([2.2, 1.1, 0.0])
662
True
63+
>>> recursive_quick_sort([2.5, -1, 0.0]) == sorted([2.5, -1, 0.0])
764
True
65+
>>> recursive_quick_sort(['d', 'a', 'b', 'c']) == sorted(['d', 'a', 'b', 'c'])
66+
True
67+
>>> recursive_quick_sort(['z', 'a', 'y', 'b', 'x', 'c'])
68+
['a', 'b', 'c', 'x', 'y', 'z']
69+
>>> import random
70+
>>> collection = random.sample(range(-50, 50), 100)
71+
>>> recursive_quick_sort(collection) == sorted(collection)
72+
True
73+
>>> import string
74+
>>> collection = random.choices(string.ascii_letters + string.digits, k=100)
75+
>>> recursive_quick_sort(collection) == sorted(collection)
76+
True
77+
>>> recursive_quick_sort([1, "a"]) # doctest: +IGNORE_EXCEPTION_DETAIL
78+
Traceback (most recent call last):
79+
...
80+
TypeError: '<=' not supported between instances of 'str' and 'int'
881
"""
9-
if len(data) <= 1:
10-
return data
11-
else:
12-
return [
13-
*quick_sort([e for e in data[1:] if e <= data[0]]),
14-
data[0],
15-
*quick_sort([e for e in data[1:] if e > data[0]]),
16-
]
82+
if len(collection) <= 1:
83+
return collection
84+
return [
85+
*recursive_quick_sort(
86+
[item for item in collection[1:] if item <= collection[0]]
87+
),
88+
collection[0],
89+
*recursive_quick_sort(
90+
[item for item in collection[1:] if item > collection[0]]
91+
),
92+
]
1793

1894

1995
if __name__ == "__main__":
20-
import doctest
96+
from doctest import testmod
97+
98+
testmod()
2199

22-
doctest.testmod()
100+
user_input = input("Enter numbers separated by a comma:\n").strip()
101+
unsorted = [int(item) for item in user_input.split(",")]
102+
print(f"{recursive_quick_sort(unsorted) = }")

‎tests/test_sorts.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from sorts.quick_sort_3_partition import three_way_radix_quicksort
4949
from sorts.recursive_insertion_sort import rec_insertion_sort
5050
from sorts.recursive_mergesort_array import merge
51+
from sorts.recursive_quick_sort import recursive_quick_sort
5152
from sorts.reverse_selection import reverse_selection_sort
5253
from sorts.reversort import reversort
5354
from sorts.selection_sort import selection_sort
@@ -117,6 +118,7 @@ def test_intro_sort_heap_fallback_preserves_surrounding_items(max_depth: int) ->
117118
pancake_sort,
118119
patience_sort,
119120
quick_sort,
121+
recursive_quick_sort,
120122
reverse_selection_sort,
121123
reversort,
122124
selection_sort,
@@ -196,6 +198,7 @@ def test_rec_insertion_sort(case) -> None:
196198
odd_even_transposition,
197199
pancake_sort,
198200
patience_sort,
201+
recursive_quick_sort,
199202
reverse_selection_sort,
200203
reversort,
201204
selection_sort,

0 commit comments

Comments
 (0)