Skip to content

Commit f465ad7

Browse files
Type recursive quick sort for any comparable items (#15490)
* Type recursive quick sort for any comparable items Part of #15234 * Cover recursive quick sort in the comparison-sort battery Part of #15234 * Replace placeholder test file with comparison-sort coverage Part of #15234 * Document the comparison operators recursive quick sort actually uses The partition uses <= and >, so the Comparable protocol should declare __le__ and __gt__ as well as __lt__. * Apply batched suggestions from code review Co-authored-by: Christian Clauss <cclauss@me.com> * Update recursive_quick_sort.py --------- Co-authored-by: Christian Clauss <cclauss@me.com>
1 parent 50dff2c commit f465ad7

2 files changed

Lines changed: 53 additions & 9 deletions

File tree

‎sorts/recursive_quick_sort.py‎

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,60 @@
1-
def quick_sort(data: list) -> list:
2-
"""
3-
>>> for data in ([2, 1, 0], [2.2, 1.1, 0], "quick_sort"):
1+
"""
2+
A pure Python implementation of a recursive quick sort.
3+
4+
For doctests run the following command:
5+
python3 -m doctest -v recursive_quick_sort.py
6+
7+
For manual testing run:
8+
python3 recursive_quick_sort.py
9+
"""
10+
11+
from typing import Any, Protocol
12+
13+
14+
class Comparable(Protocol):
15+
def __ge__(self, other: Any, /) -> bool: ...
16+
def __le__(self, other: Any, /) -> bool: ...
17+
18+
19+
def quick_sort[T: Comparable](data: list[T]) -> list[T]:
20+
"""Sort a list of mutually comparable items with recursive quick sort.
21+
22+
Returns a new list. Items must be mutually orderable. Mixing types that
23+
cannot be compared raises ``TypeError`` instead of returning a silently
24+
wrong order.
25+
26+
Examples:
27+
>>> quick_sort([2, 1, 0])
28+
[0, 1, 2]
29+
>>> quick_sort([2.2, 1.1, 0])
30+
[0, 1.1, 2.2]
31+
>>> quick_sort(["c", "a", "b"])
32+
['a', 'b', 'c']
33+
>>> quick_sort([])
34+
[]
35+
>>> quick_sort([0])
36+
[0]
37+
>>> quick_sort([2.5, -1, 0.0]) == sorted([2.5, -1, 0.0])
38+
True
39+
>>> quick_sort(list("quick_sort")) == sorted("quick_sort")
40+
True
41+
>>> quick_sort([1, "a"])
42+
Traceback (most recent call last):
43+
...
44+
TypeError: '<=' not supported between instances of 'str' and 'int'
45+
>>> for data in ([2, 1, 0], [2.2, 1.1, 0], list("quick_sort")):
446
... quick_sort(data) == sorted(data)
547
True
648
True
749
True
850
"""
951
if len(data) <= 1:
1052
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-
]
53+
return [
54+
*quick_sort([item for item in data[1:] if item <= data[0]]),
55+
data[0],
56+
*quick_sort([item for item in data[1:] if item > data[0]]),
57+
]
1758

1859

1960
if __name__ == "__main__":

‎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 quick_sort as 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)