Skip to content

Commit b40a859

Browse files
committed
fix: respect start/end boundaries in intro_sort heap-sort fallback
The heap_sort() call in intro_sort() ignored the start and end parameters, causing elements outside the requested range to be reordered when max_depth reached zero and the algorithm fell back to heap sort. Add optional start/end parameters to heapify() and heap_sort(), with default values preserving existing whole-array behavior. Update the intro_sort() call site to pass the correct range. Add a regression doctest for the subrange heap-sort fallback case. Fixes #15434
1 parent 2525255 commit b40a859

1 file changed

Lines changed: 21 additions & 14 deletions

File tree

‎sorts/intro_sort.py‎

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,28 +44,30 @@ def insertion_sort[T: Comparable](
4444

4545

4646
def heapify[T: Comparable](
47-
array: list[T], index: int, heap_size: int
47+
array: list[T], index: int, heap_size: int, start: int = 0
4848
) -> None: # Max Heap
4949
"""
5050
>>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]
5151
>>> heapify(array, len(array) // 2, len(array))
5252
"""
5353
largest = index
54-
left_index = 2 * index + 1 # Left Node
55-
right_index = 2 * index + 2 # Right Node
54+
left_index = 2 * (index - start) + 1 + start
55+
right_index = 2 * (index - start) + 2 + start
5656

57-
if left_index < heap_size and array[largest] < array[left_index]:
57+
if left_index < start + heap_size and array[largest] < array[left_index]:
5858
largest = left_index
5959

60-
if right_index < heap_size and array[largest] < array[right_index]:
60+
if right_index < start + heap_size and array[largest] < array[right_index]:
6161
largest = right_index
6262

6363
if largest != index:
6464
array[index], array[largest] = array[largest], array[index]
65-
heapify(array, largest, heap_size)
65+
heapify(array, largest, heap_size, start)
6666

6767

68-
def heap_sort[T: Comparable](array: list[T]) -> list[T]:
68+
def heap_sort[T: Comparable](
69+
array: list[T], start: int = 0, end: int | None = None
70+
) -> list[T]:
6971
"""
7072
>>> heap_sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12])
7173
[1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79]
@@ -76,14 +78,16 @@ def heap_sort[T: Comparable](array: list[T]) -> list[T]:
7678
>>> heap_sort([6.2, -45.54, 8465.20, 758.56, -457.0, 0, 1, 2.879, 1.7, 11.7])
7779
[-457.0, -45.54, 0, 1, 1.7, 2.879, 6.2, 11.7, 758.56, 8465.2]
7880
"""
79-
n = len(array)
81+
if end is None:
82+
end = len(array)
83+
n = end - start
8084

81-
for i in range(n // 2, -1, -1):
82-
heapify(array, i, n)
85+
for i in range(start + n // 2, start - 1, -1):
86+
heapify(array, i, n, start)
8387

84-
for i in range(n - 1, 0, -1):
85-
array[i], array[0] = array[0], array[i]
86-
heapify(array, 0, i)
88+
for i in range(start + n - 1, start, -1):
89+
array[i], array[start] = array[start], array[i]
90+
heapify(array, start, i - start, start)
8791

8892
return array
8993

@@ -184,10 +188,13 @@ def intro_sort[T: Comparable](
184188
>>> max_depth = 2 * math.ceil(math.log2(len(array)))
185189
>>> intro_sort(array, 0, len(array), 16, max_depth)
186190
[1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79]
191+
>>> values = [100, 4, 3, 2, 1, -100]
192+
>>> intro_sort(values, start=1, end=5, size_threshold=2, max_depth=0)
193+
[100, 1, 2, 3, 4, -100]
187194
"""
188195
while end - start > size_threshold:
189196
if max_depth == 0:
190-
return heap_sort(array)
197+
return heap_sort(array, start, end)
191198
max_depth -= 1
192199
pivot = median_of_3(array, start, start + ((end - start) // 2) + 1, end - 1)
193200
p = partition(array, start, end, pivot)

0 commit comments

Comments
 (0)