TheAlgorithms/Python · #15441

fix(sorts): make smoothsort generic over Comparable items

wanjinhao1 · merged Sep 26, 20262 files · 27 + / 10 −
sorts/smoothsort.py25 + / 10 −
@@ -10,14 +10,21 @@     https://www.cs.utexas.edu/~EWD/ewd07xx/EWD796a.PDF """ +from typing import Any, Protocol+++class Comparable(Protocol):+    def __lt__(self, other: Any, /) -> bool: ...++ # Precomputed Leonardo numbers: L(0)=1, L(1)=1, L(k)=L(k-1)+L(k-2)+1. # 46 values comfortably cover all practical list sizes. _LEONARDO: list[int] = [1, 1] while _LEONARDO[-1] < 2**31:     _LEONARDO.append(_LEONARDO[-1] + _LEONARDO[-2] + 1)  -def _sift(seq: list[int], root: int, order: int) -> None:+def _sift[T: Comparable](seq: list[T], root: int, order: int) -> None:     """     Restore the max-heap property within a Leonardo tree of the given ``order``. @@ -59,20 +66,20 @@ def _sift(seq: list[int], root: int, order: int) -> None:         right = root - 1  # right child root         left = root - 1 - _LEONARDO[order - 2]  # left child root -        if seq[left] >= seq[right] and seq[left] > seq[root]:+        if not (seq[left] < seq[right]) and seq[root] < seq[left]:             seq[root], seq[left] = seq[left], seq[root]             root = left             order -= 1-        elif seq[right] > seq[left] and seq[right] > seq[root]:+        elif seq[left] < seq[right] and seq[root] < seq[right]:             seq[root], seq[right] = seq[right], seq[root]             root = right             order -= 2         else:             break  -def _trinkle(-    seq: list[int],+def _trinkle[T: Comparable](+    seq: list[T],     pos: int,     heap_sizes: list[int],     idx: int,@@ -105,14 +112,14 @@ def _trinkle(     """     while idx > 0:         prev_root = pos - _LEONARDO[heap_sizes[idx]]-        if seq[pos] >= seq[prev_root]:+        if not (seq[pos] < seq[prev_root]):             break-        # Only swap if prev_root is also >= its own children; otherwise+        # Only swap if prev_root is also > its own children; otherwise         # moving it would break the heap on the left side.         if heap_sizes[idx] > 1:             right = pos - 1             left = pos - 1 - _LEONARDO[heap_sizes[idx] - 2]-            if seq[prev_root] <= seq[right] or seq[prev_root] <= seq[left]:+            if not (seq[right] < seq[prev_root]) or not (seq[left] < seq[prev_root]):                 break         seq[pos], seq[prev_root] = seq[prev_root], seq[pos]         pos = prev_root@@ -121,7 +128,7 @@ def _trinkle(     _sift(seq, pos, heap_sizes[idx])  -def smoothsort(seq: list[int]) -> list[int]:+def smoothsort[T: Comparable](seq: list[T]) -> list[T]:     """     Sort a list in-place using the Smoothsort algorithm and return it. @@ -131,7 +138,7 @@ def smoothsort(seq: list[int]) -> list[int]:     whose structure mirrors the sorted prefix of the sequence.      Args:-        seq: A list of integers to sort.+        seq: A list of mutually comparable items to sort.      Returns:         The same list object, sorted in ascending order.@@ -147,10 +154,18 @@ def smoothsort(seq: list[int]) -> list[int]:         [1, 2, 3, 4, 5]         >>> smoothsort([3, 3, 2, 1, 2])         [1, 2, 2, 3, 3]+        >>> smoothsort(["d", "a", "c", "b"])+        ['a', 'b', 'c', 'd']+        >>> smoothsort([2.5, -1, 0.0])+        [-1, 0.0, 2.5]         >>> smoothsort([1, 2, 3, 4, 5])         [1, 2, 3, 4, 5]         >>> smoothsort([-3, 0, -1, 5, 2])         [-3, -1, 0, 2, 5]+        >>> smoothsort([1, "a"])+        Traceback (most recent call last):+            ...+        TypeError: '<' not supported between instances of 'str' and 'int'     """     n = len(seq)     if n < 2:
tests/test_sorts.py2 + / 0 −
@@ -51,6 +51,7 @@ from sorts.selection_sort import selection_sort from sorts.shell_sort import shell_sort from sorts.shrink_shell_sort import shell_sort as shrink_shell_sort+from sorts.smoothsort import smoothsort from sorts.stooge_sort import stooge_sort from sorts.strand_sort import strand_sort from sorts.tim_sort import tim_sort@@ -92,6 +93,7 @@ def test_heap_sort() -> None:     selection_sort,     shell_sort,     shrink_shell_sort,+    smoothsort,     stooge_sort,     strand_sort,     three_way_radix_quicksort,