Skip to content

Commit f85cb69

Browse files
flash sort algorithm added
1 parent 7530a41 commit f85cb69

1 file changed

Lines changed: 161 additions & 0 deletions

File tree

sorts/flash_sort.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Flash Sort Algorithm Implementation
4+
5+
Flash sort is a distribution sorting algorithm showing linear computational
6+
complexity O(n) for uniformly distributed datasets and relatively little
7+
additional memory requirement. The basic idea is to use the distribution
8+
of the values to be sorted to determine their approximate final positions
9+
directly, without comparing and moving each element through many intermediate
10+
positions as done by other algorithms.
11+
12+
The algorithm was developed by Karl-Dietrich Neubert in 1998 and builds upon
13+
the idea of bucket sort. It works by classifying elements into classes and
14+
then sorting each class.
15+
16+
Time Complexity:
17+
- Best Case: O(n) when data is uniformly distributed
18+
- Average Case: O(n + k) where k is the number of classes
19+
- Worst Case: O(n²) when data is not uniformly distributed
20+
21+
Space Complexity: O(k) where k is the number of classes
22+
23+
Source: https://en.wikipedia.org/wiki/Flashsort
24+
"""
25+
26+
from __future__ import annotations
27+
28+
29+
def flash_sort(arr: list[int | float]) -> list[int | float]:
30+
"""
31+
Sorts a list using the Flash Sort algorithm.
32+
33+
Flash sort is particularly efficient for uniformly distributed data.
34+
It uses the distribution of values to determine approximate positions.
35+
36+
Args:
37+
arr: List of integers or floats to be sorted
38+
39+
Returns:
40+
Sorted list in ascending order
41+
42+
Examples:
43+
>>> flash_sort([4, 2, 7, 1, 9, 3])
44+
[1, 2, 3, 4, 7, 9]
45+
>>> flash_sort([])
46+
[]
47+
>>> flash_sort([5])
48+
[5]
49+
>>> flash_sort([3, 3, 3, 3])
50+
[3, 3, 3, 3]
51+
>>> flash_sort([-1, -5, 0, 3, 2])
52+
[-5, -1, 0, 2, 3]
53+
>>> flash_sort([1.5, 2.3, 0.1, 3.7, 1.2])
54+
[0.1, 1.2, 1.5, 2.3, 3.7]
55+
>>> flash_sort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
56+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
57+
>>> import random
58+
>>> data = random.sample(range(100), 20)
59+
>>> flash_sort(data) == sorted(data)
60+
True
61+
>>> flash_sort([42])
62+
[42]
63+
>>> flash_sort([2.5, 1.1, 3.3, 2.5, 1.1])
64+
[1.1, 1.1, 2.5, 2.5, 3.3]
65+
"""
66+
if len(arr) <= 1:
67+
return arr.copy()
68+
69+
# Create a copy to avoid modifying the original array
70+
result = arr.copy()
71+
n = len(result)
72+
73+
# Find min and max values
74+
min_val = min(result)
75+
max_val = max(result)
76+
77+
# If all elements are the same, return the array
78+
if min_val == max_val:
79+
return result
80+
81+
# Number of classes (buckets) - typically n/10 to n/5 works well
82+
m = max(1, int(0.45 * n))
83+
84+
# Initialize class sizes array
85+
class_sizes = [0] * m
86+
87+
# Calculate class sizes
88+
c1 = (m - 1) / (max_val - min_val)
89+
90+
for value in result:
91+
class_index = int(c1 * (value - min_val))
92+
if class_index >= m:
93+
class_index = m - 1
94+
class_sizes[class_index] += 1
95+
96+
# Calculate cumulative class sizes (positions)
97+
for i in range(1, m):
98+
class_sizes[i] += class_sizes[i - 1]
99+
100+
# Permutation phase
101+
hold = result[0]
102+
j = 0
103+
k = m - 1
104+
105+
while j < n - 1:
106+
while j >= class_sizes[k]:
107+
k -= 1
108+
109+
flash = int(c1 * (hold - min_val))
110+
if flash >= m:
111+
flash = m - 1
112+
113+
while j < class_sizes[flash]:
114+
k = flash
115+
class_sizes[k] -= 1
116+
result[j], result[class_sizes[k]] = result[class_sizes[k]], result[j]
117+
hold = result[j]
118+
j += 1
119+
flash = int(c1 * (hold - min_val))
120+
if flash >= m:
121+
flash = m - 1
122+
123+
j += 1
124+
if j < n:
125+
hold = result[j]
126+
127+
# Insertion sort for final sorting within classes
128+
for i in range(1, n):
129+
key = result[i]
130+
j = i - 1
131+
while j >= 0 and result[j] > key:
132+
result[j + 1] = result[j]
133+
j -= 1
134+
result[j + 1] = key
135+
136+
return result
137+
138+
139+
if __name__ == "__main__":
140+
from doctest import testmod
141+
142+
testmod()
143+
144+
# Additional test cases
145+
test_cases: list[list[int | float]] = [
146+
[64, 34, 25, 12, 22, 11, 90],
147+
[5, 2, 4, 6, 1, 3],
148+
[1],
149+
[],
150+
[3, 3, 3, 3],
151+
[-1, -3, 2, 0, -5],
152+
[1.1, 2.2, 0.5, 3.3, 1.5]
153+
]
154+
155+
for test_case in test_cases:
156+
sorted_result = flash_sort(test_case)
157+
expected = sorted(test_case)
158+
assert sorted_result == expected, f"Failed for {test_case}"
159+
print(f"✓ {test_case} -> {sorted_result}")
160+
161+
print("All tests passed!")

0 commit comments

Comments
 (0)