Skip to content

Commit f5eceed

Browse files
Aayaan SinghAayaan Singh
authored andcommitted
Addition of Library_sort
1 parent 215c1f0 commit f5eceed

1 file changed

Lines changed: 105 additions & 0 deletions

File tree

‎sorts/library_sort.py‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
from typing import List
2+
3+
4+
def library_sort(collection: List[int], reverse: bool = False) -> List[int]:
5+
"""
6+
A pure Python implementation of library sort (also called gapped insertion sort).
7+
8+
It w orks like insertion sort, but leaves empty gaps in the array so a new item can
9+
be placed without shifting everything after it. When the gaps fill up, the array is
10+
rebalanced. Expected time is O(n log n).
11+
12+
Reference: https://en.wikipedia.org/wiki/Library_sort
13+
14+
For doctests run the following command:
15+
python3 -m doctest -v library_sort.py
16+
17+
For manual testing run:
18+
python3 library_sort.py
19+
Time Complexity: O(N log N) average, O(N^2) worst-case
20+
Space Complexity: O(N)
21+
22+
Examples:
23+
>>> library_sort([5, 2, 9, 1, 5, 6])
24+
[1, 2, 5, 5, 6, 9]
25+
>>> library_sort([3, 1, 4, 1, 5, 9, 2])
26+
[1, 1, 2, 3, 4, 5, 9]
27+
>>> library_sort([])
28+
[]
29+
>>> library_sort([1])
30+
[1]
31+
>>> library_sort([5, 2, 9, 1], reverse=True)
32+
[9, 5, 2, 1]
33+
"""
34+
if not collection:
35+
return []
36+
37+
n = len(collection)
38+
gapped = [None] * (2 * n)
39+
gapped[0] = collection[0]
40+
41+
for i in range(1, n):
42+
val = collection[i]
43+
valid_indices = [idx for idx, x in enumerate(gapped) if x is not None]
44+
valid_vals = [gapped[idx] for idx in valid_indices]
45+
46+
low, high = 0, len(valid_vals) - 1
47+
pos = len(valid_vals)
48+
while low <= high:
49+
mid = (low + high) // 2
50+
if valid_vals[mid] >= val:
51+
pos = mid
52+
high = mid - 1
53+
else:
54+
low = mid + 1
55+
56+
if pos == len(valid_vals):
57+
target_idx = valid_indices[-1] + 1 if valid_indices else 0
58+
else:
59+
target_idx = valid_indices[pos]
60+
61+
if target_idx < len(gapped) and gapped[target_idx] is None:
62+
gapped[target_idx] = val
63+
else:
64+
current_elements = [x for x in gapped if x is not None]
65+
current_elements.append(val)
66+
current_elements.sort()
67+
68+
gapped = [None] * (2 * len(current_elements))
69+
step = len(gapped) // len(current_elements)
70+
for idx, elem in enumerate(current_elements):
71+
gapped[idx * step] = elem
72+
73+
sorted_arr = [x for x in gapped if x is not None]
74+
if reverse:
75+
sorted_arr.reverse()
76+
return sorted_arr
77+
78+
79+
if __name__ == "__main__":
80+
import doctest
81+
82+
doctest.testmod()
83+
84+
print("\nLibrarySort Interactive Testing")
85+
print("=" * 40)
86+
87+
try:
88+
user_input = input("Enter numbers separated by a comma:\n").strip()
89+
if user_input == "":
90+
unsorted = []
91+
else:
92+
unsorted = [int(item.strip()) for item in user_input.split(",")]
93+
94+
print(f"\nOriginal: {unsorted}")
95+
sorted_list = library_sort(unsorted)
96+
print(f"Sorted: {sorted_list}")
97+
98+
# Test reverse
99+
sorted_reverse = library_sort(unsorted, reverse=True)
100+
print(f"Reverse: {sorted_reverse}")
101+
102+
except ValueError:
103+
print("Invalid input. Please enter valid integers separated by commas.")
104+
except KeyboardInterrupt:
105+
print("\n\nGoodbye!")

0 commit comments

Comments
 (0)