Skip to content

Commit c4d6a2a

Browse files
Felix-mingcclauss
andauthored
sorts: type intro sort for comparable items (#15403)
* Refactor sorting functions to use generics * test: cover intro sort comparable items * Placate ruff rule PT007 * test: include intro sort in shared sort suite * Update test_sorts.py * Delete tests/test_intro_sort.py --------- Co-authored-by: Christian Clauss <cclauss@me.com>
1 parent 65b1482 commit c4d6a2a

2 files changed

Lines changed: 31 additions & 15 deletions

File tree

‎sorts/intro_sort.py‎

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55
"""
66

77
import math
8+
from typing import Any, Protocol
89

910

10-
def insertion_sort(array: list, start: int = 0, end: int = 0) -> list:
11+
class Comparable(Protocol):
12+
def __lt__(self, other: Any, /) -> bool: ...
13+
14+
15+
def insertion_sort[T: Comparable](
16+
array: list[T], start: int = 0, end: int = 0
17+
) -> list[T]:
1118
"""
1219
>>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]
1320
>>> insertion_sort(array, 0, len(array))
@@ -36,7 +43,9 @@ def insertion_sort(array: list, start: int = 0, end: int = 0) -> list:
3643
return array
3744

3845

39-
def heapify(array: list, index: int, heap_size: int) -> None: # Max Heap
46+
def heapify[T: Comparable](
47+
array: list[T], index: int, heap_size: int
48+
) -> None: # Max Heap
4049
"""
4150
>>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]
4251
>>> heapify(array, len(array) // 2, len(array))
@@ -56,7 +65,7 @@ def heapify(array: list, index: int, heap_size: int) -> None: # Max Heap
5665
heapify(array, largest, heap_size)
5766

5867

59-
def heap_sort(array: list) -> list:
68+
def heap_sort[T: Comparable](array: list[T]) -> list[T]:
6069
"""
6170
>>> heap_sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12])
6271
[1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79]
@@ -79,9 +88,9 @@ def heap_sort(array: list) -> list:
7988
return array
8089

8190

82-
def median_of_3(
83-
array: list, first_index: int, middle_index: int, last_index: int
84-
) -> int:
91+
def median_of_3[T: Comparable](
92+
array: list[T], first_index: int, middle_index: int, last_index: int
93+
) -> T:
8594
"""
8695
>>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]
8796
>>> median_of_3(array, 0, ((len(array) - 0) // 2) + 1, len(array) - 1)
@@ -93,19 +102,19 @@ def median_of_3(
93102
>>> median_of_3(array, 0, ((len(array) - 0) // 2) + 1, len(array) - 1)
94103
14
95104
"""
96-
if (array[first_index] > array[middle_index]) != (
97-
array[first_index] > array[last_index]
105+
if (array[middle_index] < array[first_index]) != (
106+
array[last_index] < array[first_index]
98107
):
99108
return array[first_index]
100-
elif (array[middle_index] > array[first_index]) != (
101-
array[middle_index] > array[last_index]
109+
elif (array[first_index] < array[middle_index]) != (
110+
array[last_index] < array[middle_index]
102111
):
103112
return array[middle_index]
104113
else:
105114
return array[last_index]
106115

107116

108-
def partition(array: list, low: int, high: int, pivot: int) -> int:
117+
def partition[T: Comparable](array: list[T], low: int, high: int, pivot: T) -> int:
109118
"""
110119
>>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]
111120
>>> partition(array, 0, len(array), 12)
@@ -134,7 +143,7 @@ def partition(array: list, low: int, high: int, pivot: int) -> int:
134143
i += 1
135144

136145

137-
def sort(array: list) -> list:
146+
def sort[T: Comparable](array: list[T]) -> list[T]:
138147
"""
139148
:param collection: some mutable ordered collection with heterogeneous
140149
comparable items inside
@@ -155,6 +164,10 @@ def sort(array: list) -> list:
155164
[0.3, 1.0, 1.7, 2.1, 3.3]
156165
>>> sort(['d', 'a', 'b', 'e', 'c'])
157166
['a', 'b', 'c', 'd', 'e']
167+
>>> sort([1, 'a']) # doctest: +IGNORE_EXCEPTION_DETAIL
168+
Traceback (most recent call last):
169+
...
170+
TypeError: ...
158171
"""
159172
if len(array) == 0:
160173
return array
@@ -163,9 +176,9 @@ def sort(array: list) -> list:
163176
return intro_sort(array, 0, len(array), size_threshold, max_depth)
164177

165178

166-
def intro_sort(
167-
array: list, start: int, end: int, size_threshold: int, max_depth: int
168-
) -> list:
179+
def intro_sort[T: Comparable](
180+
array: list[T], start: int, end: int, size_threshold: int, max_depth: int
181+
) -> list[T]:
169182
"""
170183
>>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]
171184
>>> max_depth = 2 * math.ceil(math.log2(len(array)))

‎tests/test_sorts.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from sorts.gnome_sort import gnome_sort
3535
from sorts.heap_sort import heap_sort
3636
from sorts.insertion_sort import insertion_sort
37+
from sorts.intro_sort import sort as intro_sort
3738
from sorts.iterative_merge_sort import iter_merge_sort
3839
from sorts.merge_sort import merge_sort
3940
from sorts.odd_even_sort import odd_even_sort
@@ -71,6 +72,7 @@ def test_heap_sort() -> None:
7172
gnome_sort,
7273
heap_sort,
7374
insertion_sort,
75+
intro_sort,
7476
iter_merge_sort,
7577
merge,
7678
merge_sort,
@@ -144,6 +146,7 @@ def test_rec_insertion_sort(case) -> None:
144146
exchange_sort,
145147
gnome_sort,
146148
insertion_sort,
149+
intro_sort,
147150
merge,
148151
merge_sort,
149152
odd_even_sort,

0 commit comments

Comments
 (0)