Skip to content

Commit f988f2c

Browse files
authored
Refactor quick_sort to use in-place sorting for improved space complexity
This commit refactors the quick_sort function to use an in-place sorting approach instead of creating new lists during the partitioning process. **Changes made:** - Introduced a helper function `_quick_sort(collection, low, high)` that performs the recursive in-place sorting - Implemented `_partition(collection, low, high)` using the Lomuto partition scheme for in-place partitioning - The main `quick_sort(collection)` function now sorts the list in-place and returns it - Removed the list comprehensions that created new `lesser` and `greater` lists - Replaced `collection.pop()` with in-place swapping **Benefits:** - Improved space complexity: O(log n) for the recursion stack instead of O(n) for creating new lists - More memory-efficient, especially for large collections - Maintains the same O(n log n) average time complexity - Still uses random pivot selection for better average-case performance
1 parent e2a78d4 commit f988f2c

File tree

1 file changed

+47
-18
lines changed

1 file changed

+47
-18
lines changed

sorts/quick_sort.py

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,75 @@
77
For manual testing run:
88
python3 quick_sort.py
99
"""
10-
1110
from __future__ import annotations
1211

1312
from random import randrange
1413

1514

1615
def quick_sort(collection: list) -> list:
17-
"""A pure Python implementation of quicksort algorithm.
16+
"""A pure Python implementation of quicksort algorithm using in-place sorting.
1817
1918
:param collection: a mutable collection of comparable items
2019
:return: the same collection ordered in ascending order
2120
2221
Examples:
2322
>>> quick_sort([0, 5, 3, 2, 2])
2423
[0, 2, 2, 3, 5]
24+
2525
>>> quick_sort([])
2626
[]
27+
2728
>>> quick_sort([-2, 5, 0, -45])
2829
[-45, -2, 0, 5]
2930
"""
30-
# Base case: if the collection has 0 or 1 elements, it is already sorted
31-
if len(collection) < 2:
32-
return collection
31+
# Call the helper function to sort in-place
32+
_quick_sort(collection, 0, len(collection) - 1)
33+
return collection
34+
35+
36+
def _quick_sort(collection: list, low: int, high: int) -> None:
37+
"""Helper function that performs in-place quicksort.
38+
39+
:param collection: the list to sort
40+
:param low: starting index of the partition
41+
:param high: ending index of the partition
42+
"""
43+
if low < high:
44+
# Partition the array and get the pivot index
45+
pivot_index = _partition(collection, low, high)
46+
# Recursively sort elements before and after partition
47+
_quick_sort(collection, low, pivot_index - 1)
48+
_quick_sort(collection, pivot_index + 1, high)
49+
50+
51+
def _partition(collection: list, low: int, high: int) -> int:
52+
"""In-place partitioning using Lomuto partition scheme.
53+
54+
:param collection: the list to partition
55+
:param low: starting index of the partition
56+
:param high: ending index of the partition
57+
:return: the final pivot index after partitioning
58+
"""
59+
# Randomly select a pivot index and swap with the last element
60+
pivot_index = randrange(low, high + 1)
61+
collection[pivot_index], collection[high] = collection[high], collection[pivot_index]
62+
pivot = collection[high]
3363

34-
# Randomly select a pivot index and remove the pivot element from the collection
35-
pivot_index = randrange(len(collection))
36-
pivot = collection.pop(pivot_index)
64+
# Index of smaller element (elements <= pivot will be moved to left of this)
65+
i = low - 1
3766

38-
# Partition the remaining elements into two groups: lesser or equal, and greater
39-
lesser = [item for item in collection if item <= pivot]
40-
greater = [item for item in collection if item > pivot]
67+
# Traverse through all elements and move smaller elements to the left
68+
for j in range(low, high):
69+
if collection[j] <= pivot:
70+
i += 1
71+
collection[i], collection[j] = collection[j], collection[i]
4172

42-
# Recursively sort the lesser and greater groups, and combine with the pivot
43-
return [*quick_sort(lesser), pivot, *quick_sort(greater)]
73+
# Place pivot in its correct position
74+
collection[i + 1], collection[high] = collection[high], collection[i + 1]
75+
return i + 1
4476

4577

4678
if __name__ == "__main__":
47-
# Get user input and convert it into a list of integers
48-
user_input = input("Enter numbers separated by a comma:\n").strip()
49-
unsorted = [int(item) for item in user_input.split(",")]
79+
import doctest
5080

51-
# Print the result of sorting the user-provided list
52-
print(quick_sort(unsorted))
81+
doctest.testmod()

0 commit comments

Comments
 (0)