Skip to content

Commit 09b09f9

Browse files
sorts: type six algorithms for comparable items
1 parent 5ce6733 commit 09b09f9

7 files changed

Lines changed: 150 additions & 54 deletions

File tree

sorts/cocktail_shaker_sort.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@
44
https://en.wikipedia.org/wiki/Cocktail_shaker_sort
55
"""
66

7+
from typing import Protocol
78

8-
def cocktail_shaker_sort(arr: list[int]) -> list[int]:
9+
10+
class Comparable(Protocol):
11+
def __lt__(self, other: object, /) -> bool: ...
12+
13+
14+
15+
16+
17+
def cocktail_shaker_sort[T: Comparable](arr: list[T]) -> list[T]:
918
"""
1019
Sorts a list using the Cocktail Shaker Sort algorithm.
1120
@@ -28,7 +37,12 @@ def cocktail_shaker_sort(arr: list[int]) -> list[int]:
2837
Traceback (most recent call last):
2938
...
3039
TypeError: 'tuple' object does not support item assignment
31-
"""
40+
41+
>>> cocktail_shaker_sort(["elderberry", "banana", "date", "apple", "cherry"])
42+
['apple', 'banana', 'cherry', 'date', 'elderberry']
43+
>>> cocktail_shaker_sort([3.2, -1.1, 2.4, 0.5])
44+
[-1.1, 0.5, 2.4, 3.2]
45+
"""
3246
start, end = 0, len(arr) - 1
3347

3448
while start < end:

sorts/comb_sort.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,17 @@
1818
python comb_sort.py
1919
"""
2020

21+
from typing import Protocol
2122

22-
def comb_sort(data: list) -> list:
23+
24+
class Comparable(Protocol):
25+
def __lt__(self, other: object, /) -> bool: ...
26+
27+
28+
29+
30+
31+
def comb_sort[T: Comparable](data: list[T]) -> list[T]:
2332
"""Pure implementation of comb sort algorithm in Python
2433
:param data: mutable collection with comparable items
2534
:return: the same collection in ascending order
@@ -32,7 +41,12 @@ def comb_sort(data: list) -> list:
3241
[-15, -7, 0, 2, 3, 8, 45, 99]
3342
>>> comb_sort([2, 0, 3, 4, 5, 6, 1])
3443
[0, 1, 2, 3, 4, 5, 6]
35-
"""
44+
45+
>>> comb_sort(["d", "a", "c", "b"])
46+
['a', 'b', 'c', 'd']
47+
>>> comb_sort([2.5, -1.0, 0.0])
48+
[-1.0, 0.0, 2.5]
49+
"""
3650
shrink_factor = 1.3
3751
gap = len(data)
3852
completed = False

sorts/cycle_sort.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,17 @@
33
Source: https://en.wikipedia.org/wiki/Cycle_sort
44
"""
55

6+
from typing import Protocol
67

7-
def cycle_sort(array: list) -> list:
8+
9+
class Comparable(Protocol):
10+
def __lt__(self, other: object, /) -> bool: ...
11+
12+
13+
14+
15+
16+
def cycle_sort[T: Comparable](array: list[T]) -> list[T]:
817
"""
918
>>> cycle_sort([4, 3, 2, 1])
1019
[1, 2, 3, 4]
@@ -17,7 +26,12 @@ def cycle_sort(array: list) -> list:
1726
1827
>>> cycle_sort([])
1928
[]
20-
"""
29+
30+
>>> cycle_sort(["d", "a", "c", "b"])
31+
['a', 'b', 'c', 'd']
32+
>>> cycle_sort([2.5, -1.0, 0.0])
33+
[-1.0, 0.0, 2.5]
34+
"""
2135
array_len = len(array)
2236
for cycle_start in range(array_len - 1):
2337
item = array[cycle_start]

sorts/double_sort.py

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,54 @@
1-
from typing import Any
2-
3-
4-
def double_sort(collection: list[Any]) -> list[Any]:
5-
"""This sorting algorithm sorts an array using the principle of bubble sort,
6-
but does it both from left to right and right to left.
7-
Hence, it's called "Double sort"
8-
:param collection: mutable ordered sequence of elements
9-
:return: the same collection in ascending order
10-
Examples:
11-
>>> double_sort([-1 ,-2 ,-3 ,-4 ,-5 ,-6 ,-7])
12-
[-7, -6, -5, -4, -3, -2, -1]
13-
>>> double_sort([])
14-
[]
15-
>>> double_sort([-1 ,-2 ,-3 ,-4 ,-5 ,-6])
16-
[-6, -5, -4, -3, -2, -1]
17-
>>> double_sort([-3, 10, 16, -42, 29]) == sorted([-3, 10, 16, -42, 29])
18-
True
19-
"""
20-
no_of_elements = len(collection)
21-
for _ in range(
22-
int(((no_of_elements - 1) / 2) + 1)
23-
): # we don't need to traverse to end of list as
24-
for j in range(no_of_elements - 1):
25-
# apply the bubble sort algorithm from left to right (or forwards)
26-
if collection[j + 1] < collection[j]:
27-
collection[j], collection[j + 1] = collection[j + 1], collection[j]
28-
# apply the bubble sort algorithm from right to left (or backwards)
29-
if collection[no_of_elements - 1 - j] < collection[no_of_elements - 2 - j]:
30-
(
31-
collection[no_of_elements - 1 - j],
32-
collection[no_of_elements - 2 - j],
33-
) = (
34-
collection[no_of_elements - 2 - j],
35-
collection[no_of_elements - 1 - j],
36-
)
37-
return collection
38-
39-
40-
if __name__ == "__main__":
41-
# allow the user to input the elements of the list on one line
42-
unsorted = [int(x) for x in input("Enter the list to be sorted: ").split() if x]
43-
print("the sorted list is")
44-
print(f"{double_sort(unsorted) = }")
1+
2+
from typing import Protocol
3+
4+
5+
class Comparable(Protocol):
6+
def __lt__(self, other: object, /) -> bool: ...
7+
8+
9+
def double_sort[T: Comparable](collection: list[T]) -> list[T]:
10+
"""This sorting algorithm sorts an array using the principle of bubble sort,
11+
but does it both from left to right and right to left.
12+
Hence, it's called "Double sort"
13+
:param collection: mutable ordered sequence of elements
14+
:return: the same collection in ascending order
15+
Examples:
16+
>>> double_sort([-1 ,-2 ,-3 ,-4 ,-5 ,-6 ,-7])
17+
[-7, -6, -5, -4, -3, -2, -1]
18+
>>> double_sort([])
19+
[]
20+
>>> double_sort([-1 ,-2 ,-3 ,-4 ,-5 ,-6])
21+
[-6, -5, -4, -3, -2, -1]
22+
>>> double_sort([-3, 10, 16, -42, 29]) == sorted([-3, 10, 16, -42, 29])
23+
True
24+
25+
>>> double_sort(["d", "a", "c", "b"])
26+
['a', 'b', 'c', 'd']
27+
>>> double_sort([2.5, -1.0, 0.0])
28+
[-1.0, 0.0, 2.5]
29+
"""
30+
no_of_elements = len(collection)
31+
for _ in range(
32+
int(((no_of_elements - 1) / 2) + 1)
33+
): # we don't need to traverse to end of list as
34+
for j in range(no_of_elements - 1):
35+
# apply the bubble sort algorithm from left to right (or forwards)
36+
if collection[j + 1] < collection[j]:
37+
collection[j], collection[j + 1] = collection[j + 1], collection[j]
38+
# apply the bubble sort algorithm from right to left (or backwards)
39+
if collection[no_of_elements - 1 - j] < collection[no_of_elements - 2 - j]:
40+
(
41+
collection[no_of_elements - 1 - j],
42+
collection[no_of_elements - 2 - j],
43+
) = (
44+
collection[no_of_elements - 2 - j],
45+
collection[no_of_elements - 1 - j],
46+
)
47+
return collection
48+
49+
50+
if __name__ == "__main__":
51+
# allow the user to input the elements of the list on one line
52+
unsorted = [int(x) for x in input("Enter the list to be sorted: ").split() if x]
53+
print("the sorted list is")
54+
print(f"{double_sort(unsorted) = }")

sorts/exchange_sort.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
def exchange_sort(numbers: list[int]) -> list[int]:
1+
from typing import Protocol
2+
3+
4+
class Comparable(Protocol):
5+
def __lt__(self, other: object, /) -> bool: ...
6+
7+
8+
def exchange_sort[T: Comparable](numbers: list[T]) -> list[T]:
29
"""
310
Uses exchange sort to sort a list of numbers.
411
Source: https://en.wikipedia.org/wiki/Sorting_algorithm#Exchange_sort
@@ -12,7 +19,12 @@ def exchange_sort(numbers: list[int]) -> list[int]:
1219
[-2, 0, 3, 5, 10]
1320
>>> exchange_sort([])
1421
[]
15-
"""
22+
23+
>>> exchange_sort(["d", "a", "c", "b"])
24+
['a', 'b', 'c', 'd']
25+
>>> exchange_sort([2.5, -1.0, 0.0])
26+
[-1.0, 0.0, 2.5]
27+
"""
1628
numbers_length = len(numbers)
1729
for i in range(numbers_length):
1830
for j in range(i + 1, numbers_length):

sorts/gnome_sort.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,17 @@
1212
python3 gnome_sort.py
1313
"""
1414

15+
from typing import Protocol
1516

16-
def gnome_sort(lst: list) -> list:
17+
18+
class Comparable(Protocol):
19+
def __lt__(self, other: object, /) -> bool: ...
20+
21+
22+
23+
24+
25+
def gnome_sort[T: Comparable](lst: list[T]) -> list[T]:
1726
"""
1827
Pure implementation of the gnome sort algorithm in Python
1928
@@ -32,7 +41,12 @@ def gnome_sort(lst: list) -> list:
3241
3342
>>> "".join(gnome_sort(list(set("Gnomes are stupid!"))))
3443
' !Gadeimnoprstu'
35-
"""
44+
45+
>>> gnome_sort(["d", "a", "c", "b"])
46+
['a', 'b', 'c', 'd']
47+
>>> gnome_sort([2.5, -1.0, 0.0])
48+
[-1.0, 0.0, 2.5]
49+
"""
3650
if len(lst) <= 1:
3751
return lst
3852

tests/test_sorts.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
import pytest
1818

1919
from sorts.binary_insertion_sort import binary_insertion_sort
20+
from sorts.cocktail_shaker_sort import cocktail_shaker_sort
21+
from sorts.comb_sort import comb_sort
22+
from sorts.cycle_sort import cycle_sort
23+
from sorts.double_sort import double_sort
24+
from sorts.exchange_sort import exchange_sort
25+
from sorts.gnome_sort import gnome_sort
2026
from sorts.bubble_sort import bubble_sort_iterative, bubble_sort_recursive
2127
from sorts.circle_sort import circle_sort
2228
from sorts.cocktail_shaker_sort import cocktail_shaker_sort
@@ -48,6 +54,12 @@ def test_heap_sort():
4854

4955
SORTS = (
5056
binary_insertion_sort,
57+
cocktail_shaker_sort,
58+
comb_sort,
59+
cycle_sort,
60+
double_sort,
61+
exchange_sort,
62+
gnome_sort,
5163
bubble_sort_iterative,
5264
circle_sort,
5365
cocktail_shaker_sort,
@@ -95,6 +107,12 @@ def test_sort_matches_builtin(sort, case):
95107
binary_insertion_sort,
96108
bubble_sort_iterative,
97109
bubble_sort_recursive,
110+
cocktail_shaker_sort,
111+
comb_sort,
112+
cycle_sort,
113+
double_sort,
114+
exchange_sort,
115+
gnome_sort,
98116
insertion_sort,
99117
],
100118
ids=lambda f: f.__name__,

0 commit comments

Comments
 (0)