Skip to content

Commit 37d1f42

Browse files
committed
Add a quicksort implementation
A standard, 2-way partition quicksort implementation. Choosing a more sophisticated algorithm for computing the pivot is a worthy experiment if the input is not already randomized (as it is guaranteed to be right now). Additionally, a 3-way partition such as the Bentley-McIlroy partition is another potential optimization and I might consider adding it as a separate quicksort algorithm for comparison in the future.
1 parent e902adf commit 37d1f42

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

sorting_algorithms.py

+51
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,57 @@ def shellsort(arr: List[float]) -> List[float]:
9696
return arr
9797

9898

99+
def quicksort(arr: List[float]) -> List[float]:
100+
def sort(lo: int, hi: int):
101+
# Instead of recursing to this base case, you can also opt for
102+
# an insertion sort at some cutoff point. I omitted that
103+
# potential optimization as I was seeing negligible speed
104+
# gains at < 10,000 elements and minor speed losses > 10,000 elements.
105+
if lo >= hi:
106+
return
107+
108+
j = _partition(arr, lo, hi)
109+
sort(lo, j - 1)
110+
sort(j + 1, hi)
111+
112+
sort(0, len(arr) - 1)
113+
return arr
114+
115+
116+
def _partition(arr: List[float], lo: int, hi: int) -> int:
117+
# One of the most important aspects of quicksort - selecting the pivot.
118+
# I am current selecting the first element as the pivot since I am
119+
# guaranteeing that the input is randomized and likely void of duplicates.
120+
pivot = arr[lo]
121+
forward_ptr = lo + 1
122+
reverse_ptr = hi
123+
124+
while True:
125+
# Find an element larger than the pivot moving left => right.
126+
while arr[forward_ptr] < pivot and forward_ptr < hi:
127+
forward_ptr += 1
128+
129+
# Find an element smaller than the pivot moving right => left.
130+
while arr[reverse_ptr] > pivot and reverse_ptr > lo:
131+
reverse_ptr -= 1
132+
133+
# Do not swap the elements when the pointers have crossed.
134+
# This means the sorted location for the pivot has been found.
135+
if forward_ptr >= reverse_ptr:
136+
break
137+
138+
# Swap the larger elements on the left with the smaller elements
139+
# on the right.
140+
arr[forward_ptr], arr[reverse_ptr] = arr[reverse_ptr], arr[forward_ptr]
141+
142+
# Place the pivot located at arr[lo] into its sorted position.
143+
arr[lo], arr[reverse_ptr] = arr[reverse_ptr], arr[lo]
144+
145+
# Return the location of the pivot's final destination as it
146+
# acts as the anchor for subsequent partitions.
147+
return reverse_ptr
148+
149+
99150
# Insertion sort for any subsequence. Helper for other
100151
# sorting algorithms like mergesort and quicksort.
101152
def _subsequence_insertion_sort(arr: List[float], lo: int, hi: int) -> None:

0 commit comments

Comments
 (0)