sorting-suite 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sorting_suite/__init__.py +33 -0
- sorting_suite/sorting.py +209 -0
- sorting_suite/testing.py +67 -0
- sorting_suite-1.0.1.dist-info/METADATA +66 -0
- sorting_suite-1.0.1.dist-info/RECORD +8 -0
- sorting_suite-1.0.1.dist-info/WHEEL +5 -0
- sorting_suite-1.0.1.dist-info/licenses/LICENSE +21 -0
- sorting_suite-1.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from .sorting import (
|
|
2
|
+
swap,
|
|
3
|
+
is_sorted,
|
|
4
|
+
reverse,
|
|
5
|
+
selection_sort,
|
|
6
|
+
shell_sort,
|
|
7
|
+
heap_sort,
|
|
8
|
+
bitonic_sort,
|
|
9
|
+
insertion_sort,
|
|
10
|
+
bogo_sort,
|
|
11
|
+
merge_sort,
|
|
12
|
+
quick_sort,
|
|
13
|
+
bubble_sort,
|
|
14
|
+
bucket_sort,
|
|
15
|
+
comb_sort,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"swap",
|
|
20
|
+
"is_sorted",
|
|
21
|
+
"reverse",
|
|
22
|
+
"selection_sort",
|
|
23
|
+
"shell_sort",
|
|
24
|
+
"heap_sort",
|
|
25
|
+
"bitonic_sort",
|
|
26
|
+
"insertion_sort",
|
|
27
|
+
"bogo_sort",
|
|
28
|
+
"merge_sort",
|
|
29
|
+
"quick_sort",
|
|
30
|
+
"bubble_sort",
|
|
31
|
+
"bucket_sort",
|
|
32
|
+
"comb_sort"
|
|
33
|
+
]
|
sorting_suite/sorting.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Swaps arr[i] and arr[j]
|
|
2
|
+
# Runtime: O(1)
|
|
3
|
+
def swap(arr, i, j):
|
|
4
|
+
temp = arr[i]
|
|
5
|
+
arr[i] = arr[j]
|
|
6
|
+
arr[j] = temp
|
|
7
|
+
|
|
8
|
+
# Checks if a list is sorted
|
|
9
|
+
# Runtime: O(n)
|
|
10
|
+
def is_sorted(arr):
|
|
11
|
+
if not arr:
|
|
12
|
+
return True
|
|
13
|
+
return all(arr[i] <= arr[i + 1] for i in range(len(arr) - 1))
|
|
14
|
+
|
|
15
|
+
# Reverses a list
|
|
16
|
+
# Call on a sorted list to reverse the sorting order
|
|
17
|
+
# Runtime: O(n)
|
|
18
|
+
def reverse(arr):
|
|
19
|
+
return arr[::-1]
|
|
20
|
+
|
|
21
|
+
# Sorts by "bubbling" large elements up into the correct spots
|
|
22
|
+
# Stable
|
|
23
|
+
# Runtime: O(n^2)
|
|
24
|
+
def bubble_sort(arr):
|
|
25
|
+
arr = arr.copy()
|
|
26
|
+
n = len(arr)
|
|
27
|
+
for i in range(n):
|
|
28
|
+
for j in range(0, n - i - 1):
|
|
29
|
+
if arr[j] > arr[j + 1]:
|
|
30
|
+
arr[j], arr[j + 1] = arr[j + 1], arr[j]
|
|
31
|
+
return arr
|
|
32
|
+
|
|
33
|
+
# Sorts by picking pivots, partioning the list into sections, and recursively sorting the parts
|
|
34
|
+
# Runtime: O(n^2)
|
|
35
|
+
def quick_sort(arr):
|
|
36
|
+
if len(arr) <= 1:
|
|
37
|
+
return arr
|
|
38
|
+
pivot = arr[len(arr) // 2]
|
|
39
|
+
left = [x for x in arr if x < pivot]
|
|
40
|
+
mid = [x for x in arr if x == pivot]
|
|
41
|
+
right = [x for x in arr if x > pivot]
|
|
42
|
+
return quick_sort(left) + mid + quick_sort(right)
|
|
43
|
+
|
|
44
|
+
# Sorts by inserting elements into the correct order one at a time
|
|
45
|
+
# Stable
|
|
46
|
+
# Runtime: O(n^2)
|
|
47
|
+
def insertion_sort(arr):
|
|
48
|
+
arr = arr.copy()
|
|
49
|
+
for i in range(1,len(arr)):
|
|
50
|
+
k = arr[i]
|
|
51
|
+
j = i - 1
|
|
52
|
+
|
|
53
|
+
while j >= 0 and arr[j] > k:
|
|
54
|
+
arr[j + 1] = arr[j]
|
|
55
|
+
j -= 1
|
|
56
|
+
|
|
57
|
+
arr[j + 1] = k
|
|
58
|
+
return arr
|
|
59
|
+
|
|
60
|
+
# Sorts by finding the next smallest elements and placing at front
|
|
61
|
+
# Runtime: O(n^2)
|
|
62
|
+
def selection_sort(arr):
|
|
63
|
+
arr = arr.copy()
|
|
64
|
+
n = len(arr)
|
|
65
|
+
for i in range(n):
|
|
66
|
+
min_inx = i
|
|
67
|
+
for j in range(i+1, n):
|
|
68
|
+
if arr[j] < arr[min_inx]:
|
|
69
|
+
min_inx = j
|
|
70
|
+
arr[i], arr[min_inx] = arr[min_inx], arr[i]
|
|
71
|
+
return arr
|
|
72
|
+
|
|
73
|
+
# Sorts by spliting the list in half and recursively sorting
|
|
74
|
+
# Stable
|
|
75
|
+
# Runtime: O(nlog(n))
|
|
76
|
+
def merge_sort(arr):
|
|
77
|
+
if len(arr) <= 1:
|
|
78
|
+
return arr
|
|
79
|
+
|
|
80
|
+
mid = len(arr) // 2
|
|
81
|
+
left = merge_sort(arr[:mid])
|
|
82
|
+
right = merge_sort(arr[mid:])
|
|
83
|
+
|
|
84
|
+
return _merge(left, right)
|
|
85
|
+
|
|
86
|
+
def _merge(left, right):
|
|
87
|
+
i = j = 0
|
|
88
|
+
result = []
|
|
89
|
+
|
|
90
|
+
while i < len(left) and j < len(right):
|
|
91
|
+
if left[i] <= right[j]:
|
|
92
|
+
result.append(left[i])
|
|
93
|
+
i += 1
|
|
94
|
+
else:
|
|
95
|
+
result.append(right[j])
|
|
96
|
+
j += 1
|
|
97
|
+
|
|
98
|
+
return result + left[i:] + right[j:]
|
|
99
|
+
|
|
100
|
+
# Sorts by randomizing the list order and checking if the list is sorted
|
|
101
|
+
# Runtime: O(inf)
|
|
102
|
+
def bogo_sort(arr):
|
|
103
|
+
import random
|
|
104
|
+
arr = arr.copy()
|
|
105
|
+
while not is_sorted(arr):
|
|
106
|
+
random.shuffle(arr)
|
|
107
|
+
return arr
|
|
108
|
+
|
|
109
|
+
# Sorts by sorting into buckets, sorting the buckets, and concatenating
|
|
110
|
+
# Stable
|
|
111
|
+
# Runtime: O(n+k), where k is number of buckets
|
|
112
|
+
def bucket_sort(arr, bucket_size=10):
|
|
113
|
+
if len(arr) == 0:
|
|
114
|
+
return arr
|
|
115
|
+
arr = arr.copy()
|
|
116
|
+
min_val, max_val = min(arr), max(arr)
|
|
117
|
+
bucket_count = (max_val - min_val) // bucket_size + 1
|
|
118
|
+
buckets = [[] for _ in range(bucket_count)]
|
|
119
|
+
|
|
120
|
+
for num in arr:
|
|
121
|
+
index = (num - min_val) // bucket_size
|
|
122
|
+
buckets[index].append(num)
|
|
123
|
+
|
|
124
|
+
sorted_arr = []
|
|
125
|
+
for bucket in buckets:
|
|
126
|
+
sorted_arr.extend(insertion_sort(bucket))
|
|
127
|
+
|
|
128
|
+
return sorted_arr
|
|
129
|
+
|
|
130
|
+
# Sorts by comparing far apart elements and moving them
|
|
131
|
+
# Runtime: O(n^2)
|
|
132
|
+
def shell_sort(arr):
|
|
133
|
+
arr = arr.copy()
|
|
134
|
+
n = len(arr)
|
|
135
|
+
gap = n // 2
|
|
136
|
+
while gap > 0:
|
|
137
|
+
for i in range(gap, n):
|
|
138
|
+
temp = arr[i]
|
|
139
|
+
j = i
|
|
140
|
+
while j >= gap and arr[j - gap] > temp:
|
|
141
|
+
arr[j] = arr[j - gap]
|
|
142
|
+
j -= gap
|
|
143
|
+
arr[j] = temp
|
|
144
|
+
gap //= 2
|
|
145
|
+
return arr
|
|
146
|
+
|
|
147
|
+
# Sorts by taking advantage of binary sequences
|
|
148
|
+
# Runtime: O(log^2(n))
|
|
149
|
+
def bitonic_sort(arr):
|
|
150
|
+
n = len(arr)
|
|
151
|
+
for k in range(2, n+1):
|
|
152
|
+
j = k // 2
|
|
153
|
+
while j > 0:
|
|
154
|
+
for i in range(0, n):
|
|
155
|
+
l = i ^ j
|
|
156
|
+
if l > i:
|
|
157
|
+
if ( ((i&k)==0) and (arr[i] > arr[l]) or ( ( (i&k)!=0) and (arr[i] < arr[l])) ):
|
|
158
|
+
temp = arr[i]
|
|
159
|
+
arr[i] = arr[l]
|
|
160
|
+
arr[l] = temp
|
|
161
|
+
j //= 2
|
|
162
|
+
|
|
163
|
+
# Sorts by using a binary min heap
|
|
164
|
+
# Runtime: O(log(n))
|
|
165
|
+
def heap_sort(arr):
|
|
166
|
+
n = len(arr)
|
|
167
|
+
|
|
168
|
+
for i in range(n//2, -1, -1):
|
|
169
|
+
__heapify(arr, n, i)
|
|
170
|
+
|
|
171
|
+
for i in range(n-1, 0, -1):
|
|
172
|
+
arr[i], arr[0] = arr[0], arr[i]
|
|
173
|
+
|
|
174
|
+
__heapify(arr, i, 0)
|
|
175
|
+
|
|
176
|
+
def __heapify(arr, n, i):
|
|
177
|
+
largest = i
|
|
178
|
+
l = 2 * i + 1
|
|
179
|
+
r = 2 * i + 2
|
|
180
|
+
|
|
181
|
+
if l < n and arr[i] < arr[l]:
|
|
182
|
+
largest = l
|
|
183
|
+
|
|
184
|
+
if r < n and arr[largest] < arr[r]:
|
|
185
|
+
largest = r
|
|
186
|
+
|
|
187
|
+
if largest != i:
|
|
188
|
+
arr[i], arr[largest] = arr[largest], arr[i]
|
|
189
|
+
__heapify(arr, n, largest)
|
|
190
|
+
|
|
191
|
+
# Sorts similarly to bubble sort, but removes turtles
|
|
192
|
+
# Runtime: O(n^2)
|
|
193
|
+
def comb_sort(arr):
|
|
194
|
+
n = len(arr)
|
|
195
|
+
s = 1.3
|
|
196
|
+
gap = n
|
|
197
|
+
sorted = False
|
|
198
|
+
|
|
199
|
+
while not sorted:
|
|
200
|
+
gap = int(gap/s)
|
|
201
|
+
if gap <= 1:
|
|
202
|
+
sorted = True
|
|
203
|
+
gap = 1
|
|
204
|
+
|
|
205
|
+
for i in range(n-gap):
|
|
206
|
+
sm = gap + i
|
|
207
|
+
if arr[i] > arr[sm]:
|
|
208
|
+
arr[i], arr[sm] = arr[sm], arr[i]
|
|
209
|
+
sorted = False
|
sorting_suite/testing.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from sorting import (
|
|
2
|
+
swap,
|
|
3
|
+
is_sorted,
|
|
4
|
+
reverse,
|
|
5
|
+
selection_sort,
|
|
6
|
+
shell_sort,
|
|
7
|
+
heap_sort,
|
|
8
|
+
insertion_sort,
|
|
9
|
+
bogo_sort,
|
|
10
|
+
merge_sort,
|
|
11
|
+
quick_sort,
|
|
12
|
+
bubble_sort,
|
|
13
|
+
bucket_sort,
|
|
14
|
+
comb_sort
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def test_sorting_functions():
|
|
18
|
+
test_cases = [
|
|
19
|
+
[],
|
|
20
|
+
[1],
|
|
21
|
+
[2, 1],
|
|
22
|
+
[4, 2, 7, 1, 3],
|
|
23
|
+
[5, 3, 8, 5, 2, 2, 9],
|
|
24
|
+
[1, 2, 3, 4, 5],
|
|
25
|
+
[5, 4, 3, 2, 1],
|
|
26
|
+
[435, 2, 1090, 123, 345, 24, 45, -1204],
|
|
27
|
+
[-90, -1, 0, 32, -4],
|
|
28
|
+
[-1],
|
|
29
|
+
[1, 1, 2, 0, 1, 1, 1, 2, 0, 1]
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
sorting_functions = [
|
|
33
|
+
selection_sort,
|
|
34
|
+
insertion_sort,
|
|
35
|
+
shell_sort,
|
|
36
|
+
heap_sort,
|
|
37
|
+
merge_sort,
|
|
38
|
+
quick_sort,
|
|
39
|
+
bubble_sort,
|
|
40
|
+
bucket_sort,
|
|
41
|
+
bogo_sort,
|
|
42
|
+
comb_sort
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
for func in sorting_functions:
|
|
46
|
+
print(f"\nTesting {func.__name__}:")
|
|
47
|
+
for arr in test_cases:
|
|
48
|
+
if func == bogo_sort and len(arr) > 3:
|
|
49
|
+
continue
|
|
50
|
+
result = func(arr)
|
|
51
|
+
print(f"Input: {arr} -> Output: {result} -> Sorted: {is_sorted(result)}")
|
|
52
|
+
|
|
53
|
+
def test_utilities():
|
|
54
|
+
print("\nTesting utility functions:")
|
|
55
|
+
|
|
56
|
+
arr = [4,5,6]
|
|
57
|
+
swap(arr, 0, 2)
|
|
58
|
+
print(f"swap([4,5,6],0,2) -> ({arr})")
|
|
59
|
+
|
|
60
|
+
arr = [1,2,3]
|
|
61
|
+
print(f"reverse([1,2,3]) -> {reverse(arr)}")
|
|
62
|
+
print(f"is_sorted([1,2,3]) -> {is_sorted([1,2,3])}")
|
|
63
|
+
print(f"is_sorted([3,1,2]) -> {is_sorted([3,1,2])}")
|
|
64
|
+
|
|
65
|
+
if __name__ == "__main__":
|
|
66
|
+
test_sorting_functions()
|
|
67
|
+
test_utilities()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sorting-suite
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: A large suite of numerical sorting algorithms in Python
|
|
5
|
+
Home-page: https://reesefairchild.github.io/sorting-suite
|
|
6
|
+
Author: Reese Fairchild
|
|
7
|
+
Author-email: rfair@uw.edu
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
**sorting-suite** is a simple Python library providing a comprehensive collection of numerical sorting algorithms, along with helpful utility functions.
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Sorting Algorithms by Average Runtime
|
|
22
|
+
|
|
23
|
+
**O(n + k)**
|
|
24
|
+
- Bucket Sort
|
|
25
|
+
|
|
26
|
+
**O(log^2 n)**
|
|
27
|
+
- Bitonic Sort (can only be used on lists with size that is multiple of 2)
|
|
28
|
+
|
|
29
|
+
**O(n log n)**
|
|
30
|
+
- Heap Sort
|
|
31
|
+
- Merge Sort
|
|
32
|
+
- Quick Sort
|
|
33
|
+
- Shell Sort
|
|
34
|
+
|
|
35
|
+
**O(n^2)**
|
|
36
|
+
- Bubble Sort
|
|
37
|
+
- Comb Sort
|
|
38
|
+
- Insertion Sort
|
|
39
|
+
- Selection Sort
|
|
40
|
+
|
|
41
|
+
**O(n!)**
|
|
42
|
+
- Bogo Sort (please do not use this one)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Stable Sorts
|
|
47
|
+
- Bucket Sort
|
|
48
|
+
- Bubble Sort
|
|
49
|
+
- Insertion Sort
|
|
50
|
+
- Merge Sort
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Utility Functions
|
|
55
|
+
|
|
56
|
+
- **`swap(a, b)`** – Swap two elements.
|
|
57
|
+
- **`is_sorted(arr)`** – Check if an array is sorted.
|
|
58
|
+
- **`reverse(arr)`** – Reverse the elements of a list. Allows above sorting functions
|
|
59
|
+
to sort in descending order, if desired.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install sorting-suite
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
sorting_suite/__init__.py,sha256=MuPClu8qmQeu7hk4bDBSnksYsvJOh2oRbovUlbxSNcw,544
|
|
2
|
+
sorting_suite/sorting.py,sha256=zu-Th-xdiyRbwpCLaVGfarYWX3mr6vihB0pA2ros2iQ,5372
|
|
3
|
+
sorting_suite/testing.py,sha256=CdpKSJdJPfkDGjSxfkaPJ-0JA2yRA7piwu-eE9Diki4,1589
|
|
4
|
+
sorting_suite-1.0.1.dist-info/licenses/LICENSE,sha256=VnhoJXSrJmUmafjcQIYfxPneQi-1HtdrB1xqlqSkgfA,1091
|
|
5
|
+
sorting_suite-1.0.1.dist-info/METADATA,sha256=kObyXL5pQ0vRlRxk1Sm62Rj_oKUuylCVnY3_pjq_6zs,1526
|
|
6
|
+
sorting_suite-1.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
sorting_suite-1.0.1.dist-info/top_level.txt,sha256=szzy3nC-gOlFPZirat3gXpqDWQ1Yhuv9Hh7xf2oISkg,14
|
|
8
|
+
sorting_suite-1.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Reese Fairchild
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sorting_suite
|