From f5eceeda3575716c99619896300f29b557dca4ee Mon Sep 17 00:00:00 2001 From: Aayaan Singh Date: Thu, 8 Oct 2026 15:13:41 +0530 Subject: [PATCH 1/3] Addition of Library_sort --- sorts/library_sort.py | 105 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 sorts/library_sort.py diff --git a/sorts/library_sort.py b/sorts/library_sort.py new file mode 100644 index 000000000000..b86692b8306c --- /dev/null +++ b/sorts/library_sort.py @@ -0,0 +1,105 @@ +from typing import List + + +def library_sort(collection: List[int], reverse: bool = False) -> List[int]: + """ + A pure Python implementation of library sort (also called gapped insertion sort). + + It w orks like insertion sort, but leaves empty gaps in the array so a new item can + be placed without shifting everything after it. When the gaps fill up, the array is + rebalanced. Expected time is O(n log n). + + Reference: https://en.wikipedia.org/wiki/Library_sort + + For doctests run the following command: + python3 -m doctest -v library_sort.py + + For manual testing run: + python3 library_sort.py + Time Complexity: O(N log N) average, O(N^2) worst-case + Space Complexity: O(N) + + Examples: + >>> library_sort([5, 2, 9, 1, 5, 6]) + [1, 2, 5, 5, 6, 9] + >>> library_sort([3, 1, 4, 1, 5, 9, 2]) + [1, 1, 2, 3, 4, 5, 9] + >>> library_sort([]) + [] + >>> library_sort([1]) + [1] + >>> library_sort([5, 2, 9, 1], reverse=True) + [9, 5, 2, 1] + """ + if not collection: + return [] + + n = len(collection) + gapped = [None] * (2 * n) + gapped[0] = collection[0] + + for i in range(1, n): + val = collection[i] + valid_indices = [idx for idx, x in enumerate(gapped) if x is not None] + valid_vals = [gapped[idx] for idx in valid_indices] + + low, high = 0, len(valid_vals) - 1 + pos = len(valid_vals) + while low <= high: + mid = (low + high) // 2 + if valid_vals[mid] >= val: + pos = mid + high = mid - 1 + else: + low = mid + 1 + + if pos == len(valid_vals): + target_idx = valid_indices[-1] + 1 if valid_indices else 0 + else: + target_idx = valid_indices[pos] + + if target_idx < len(gapped) and gapped[target_idx] is None: + gapped[target_idx] = val + else: + current_elements = [x for x in gapped if x is not None] + current_elements.append(val) + current_elements.sort() + + gapped = [None] * (2 * len(current_elements)) + step = len(gapped) // len(current_elements) + for idx, elem in enumerate(current_elements): + gapped[idx * step] = elem + + sorted_arr = [x for x in gapped if x is not None] + if reverse: + sorted_arr.reverse() + return sorted_arr + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + print("\nLibrarySort Interactive Testing") + print("=" * 40) + + try: + user_input = input("Enter numbers separated by a comma:\n").strip() + if user_input == "": + unsorted = [] + else: + unsorted = [int(item.strip()) for item in user_input.split(",")] + + print(f"\nOriginal: {unsorted}") + sorted_list = library_sort(unsorted) + print(f"Sorted: {sorted_list}") + + # Test reverse + sorted_reverse = library_sort(unsorted, reverse=True) + print(f"Reverse: {sorted_reverse}") + + except ValueError: + print("Invalid input. Please enter valid integers separated by commas.") + except KeyboardInterrupt: + print("\n\nGoodbye!") From e8af6490c86752720cba5b2820ac00a55b686265 Mon Sep 17 00:00:00 2001 From: Aayaan Singh Date: Thu, 8 Oct 2026 15:32:22 +0530 Subject: [PATCH 2/3] Add library sort (gapped insertion sort) --- sorts/library_sort.py | 187 +++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 84 deletions(-) diff --git a/sorts/library_sort.py b/sorts/library_sort.py index b86692b8306c..c7341ce97c7b 100644 --- a/sorts/library_sort.py +++ b/sorts/library_sort.py @@ -1,105 +1,124 @@ -from typing import List +""" +A pure Python implementation of library sort (also called gapped insertion sort). +It works like insertion sort, but leaves empty gaps in the array so a new item can +be placed without shifting everything after it. When the gaps fill up, the array is +rebalanced. Expected time is O(n log n). -def library_sort(collection: List[int], reverse: bool = False) -> List[int]: +Reference: https://en.wikipedia.org/wiki/Library_sort + +For doctests run the following command: +python3 -m doctest -v library_sort.py + +For manual testing run: +python3 library_sort.py +""" + +_EMPTY = object() + + +def _spread(slots: list) -> None: """ - A pure Python implementation of library sort (also called gapped insertion sort). + Redistribute the stored items evenly across all slots, keeping their order. - It w orks like insertion sort, but leaves empty gaps in the array so a new item can - be placed without shifting everything after it. When the gaps fill up, the array is - rebalanced. Expected time is O(n log n). + >>> slots = [3, 5, 7, _EMPTY, _EMPTY, _EMPTY] + >>> _spread(slots) + >>> [x if x is not _EMPTY else None for x in slots] + [3, None, 5, None, 7, None] + """ + items = [x for x in slots if x is not _EMPTY] + for i in range(len(slots)): + slots[i] = _EMPTY + for i, item in enumerate(items): + slots[i * len(slots) // len(items)] = item - Reference: https://en.wikipedia.org/wiki/Library_sort - For doctests run the following command: - python3 -m doctest -v library_sort.py +def _insert(slots: list, item) -> None: + """ + Insert item into the gapped array, keeping the stored items in sorted order. + + >>> slots = [1, _EMPTY, 5, _EMPTY] + >>> _insert(slots, 3) + >>> [x if x is not _EMPTY else None for x in slots] + [1, 3, 5, None] + """ + size = len(slots) + low, high = 0, size - 1 + # Binary search over the slots, skipping empty ones. + while low <= high: + mid = (low + high) // 2 + probe = mid + while probe <= high and slots[probe] is _EMPTY: + probe += 1 + if probe > high: + high = mid - 1 + elif slots[probe] <= item: + low = probe + 1 + else: + high = mid - 1 + + # Every stored item before `low` is <= item, every one from `low` on is > item. + if low < size and slots[low] is _EMPTY: + slots[low] = item + return + + right = low + while right < size and slots[right] is not _EMPTY: + right += 1 + left = low - 1 + while left >= 0 and slots[left] is not _EMPTY: + left -= 1 + + # Shift items towards the nearest gap to make room. + if left < 0 or (right < size and right - low <= low - 1 - left): + slots[low + 1 : right + 1] = slots[low:right] + slots[low] = item + else: + slots[left : low - 1] = slots[left + 1 : low] + slots[low - 1] = item + + +def library_sort(collection: list) -> list: + """ + A pure Python implementation of library sort (also called gapped insertion sort). + + :param collection: a collection of comparable items + :return: a new list with the items in ascending order - For manual testing run: - python3 library_sort.py - Time Complexity: O(N log N) average, O(N^2) worst-case - Space Complexity: O(N) + Time complexity: O(n log n) on average, O(n^2) in the worst case. + Space complexity: O(n) Examples: >>> library_sort([5, 2, 9, 1, 5, 6]) [1, 2, 5, 5, 6, 9] - >>> library_sort([3, 1, 4, 1, 5, 9, 2]) - [1, 1, 2, 3, 4, 5, 9] >>> library_sort([]) [] >>> library_sort([1]) [1] - >>> library_sort([5, 2, 9, 1], reverse=True) - [9, 5, 2, 1] + >>> library_sort([-2, 5, 0, -45]) + [-45, -2, 0, 5] + >>> library_sort(["d", "a", "c", "b"]) + ['a', 'b', 'c', 'd'] + >>> import random + >>> data = [random.randint(-100, 100) for _ in range(200)] + >>> library_sort(data) == sorted(data) + True """ - if not collection: - return [] - n = len(collection) - gapped = [None] * (2 * n) - gapped[0] = collection[0] - - for i in range(1, n): - val = collection[i] - valid_indices = [idx for idx, x in enumerate(gapped) if x is not None] - valid_vals = [gapped[idx] for idx in valid_indices] - - low, high = 0, len(valid_vals) - 1 - pos = len(valid_vals) - while low <= high: - mid = (low + high) // 2 - if valid_vals[mid] >= val: - pos = mid - high = mid - 1 - else: - low = mid + 1 - - if pos == len(valid_vals): - target_idx = valid_indices[-1] + 1 if valid_indices else 0 - else: - target_idx = valid_indices[pos] + if n < 2: + return list(collection) - if target_idx < len(gapped) and gapped[target_idx] is None: - gapped[target_idx] = val - else: - current_elements = [x for x in gapped if x is not None] - current_elements.append(val) - current_elements.sort() - - gapped = [None] * (2 * len(current_elements)) - step = len(gapped) // len(current_elements) - for idx, elem in enumerate(current_elements): - gapped[idx * step] = elem - - sorted_arr = [x for x in gapped if x is not None] - if reverse: - sorted_arr.reverse() - return sorted_arr + slots: list = [_EMPTY] * (2 * n) + next_spread = 1 + for count, item in enumerate(collection, start=1): + _insert(slots, item) + if count == next_spread: + _spread(slots) + next_spread *= 2 + return [x for x in slots if x is not _EMPTY] if __name__ == "__main__": - import doctest - - doctest.testmod() - - print("\nLibrarySort Interactive Testing") - print("=" * 40) - - try: - user_input = input("Enter numbers separated by a comma:\n").strip() - if user_input == "": - unsorted = [] - else: - unsorted = [int(item.strip()) for item in user_input.split(",")] - - print(f"\nOriginal: {unsorted}") - sorted_list = library_sort(unsorted) - print(f"Sorted: {sorted_list}") - - # Test reverse - sorted_reverse = library_sort(unsorted, reverse=True) - print(f"Reverse: {sorted_reverse}") - - except ValueError: - print("Invalid input. Please enter valid integers separated by commas.") - except KeyboardInterrupt: - print("\n\nGoodbye!") + user_input = input("Enter numbers separated by a comma:\n").strip() + unsorted = [int(item) for item in user_input.split(",")] + print(library_sort(unsorted)) From b4904c0bcf7e1e2e8cf534a95a4812c7f4b1ebd2 Mon Sep 17 00:00:00 2001 From: Aayaan Singh Date: Thu, 8 Oct 2026 15:37:50 +0530 Subject: [PATCH 3/3] Add type hint for item in _insert --- sorts/library_sort.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sorts/library_sort.py b/sorts/library_sort.py index c7341ce97c7b..96075d70db45 100644 --- a/sorts/library_sort.py +++ b/sorts/library_sort.py @@ -14,6 +14,8 @@ python3 library_sort.py """ +from typing import Any + _EMPTY = object() @@ -33,7 +35,7 @@ def _spread(slots: list) -> None: slots[i * len(slots) // len(items)] = item -def _insert(slots: list, item) -> None: +def _insert(slots: list, item: Any) -> None: """ Insert item into the gapped array, keeping the stored items in sorted order.