4.3. Quick Sort#
Quick sort is one of the more recently developed sorting algorithms, developed by Tony Hoare in 1959. Much like Merge Sort, Quick Sort is a divide-and-conquer algorithm and is comparison-based. It works by selecting one of the elements in the given list as pivot
and partitioning the other elements into two sub-arrays according to whether they are less than or greater than the pivot. The process is then repeated for the two sublists.
The key process in Quick Sort is partition
. The target of partition is to place the pivot (any element can be chosen to be a pivot) at its correct position in the list and put all smaller elements to the left of the pivot, and make sure all greater elements to the right of the pivot.
The process of partition is described in details, with implementation, below:
Partition
The problem of partitition requires placing the pivot (any element can be chosen to be a pivot) at its correct position in the sorted array and put all smaller elements to the left of the pivot, and all greater elements to the right of the pivot.
Although any element in the list can be chosen as the pivot, the most common choice is to choose the last element as the pivot. It makes visualization easier and the implementation of the algorithm simpler.
Once the pivot is chosen, we follow the following steps:
Take two variables to point
left
andright
of the list excludingpivot
left
points to the low index andright
points to the highest index
While
data[left] > pivot
, keep movingleft
towards rightWhile
data[right] > pivot
, keep movingright
towards leftIf
data[left] > data[right]
then swap the valuesEventually,
left >= right
, the point where they met is the new location of pivot
Below is visualization of the partition process, annotated with the implementation that follows.
The code for the partition process is as follows:
def partition(data, start, end):
pivot = data[end]
left = start
right = end - 1
while left < right:
# move left towards right
while data[left] < pivot:
left = left + 1
# move right towards left
while right > 0 and data[right] > pivot:
right = right - 1
if left < right:
data[left], data[right] = data[right], data[left]
# insert pivot into its correct place
data[left], data[end] = data[end], data[left]
return left
Now that we have the partition process, we can implement the Quick Sort algorithm by calling the partition process repeatedly on ever smaller sublists.
4.3.1. Algorithm#
The steps of the iterative QuickSort algorithm are:
Call partition on the entire array. This will place the pivot element in its correct position in the sorted array, and place all smaller elements to the left of the pivot, and all greater elements to the right of the pivot.
Call partition on the left sublist and right sublists.
Repeat the process for the left and right sublists until the base case is reached, i.e. the sublist has only one element.
Note that the sublists are not created explicitly. Instead, the algorithm uses the indices to keep track of the sublists.
4.3.2. Implementation#
def partition(data, start, end):
pivot = data[end]
left = start
right = end - 1
while left < right:
# move left towards right
while data[left] < pivot:
left = left + 1
# move right towards left
while right > 0 and data[right] > pivot:
right = right - 1
if left < right:
data[left], data[right] = data[right], data[left]
# insert pivot into its correct place
data[left], data[end] = data[end], data[left]
return left
def quick_sort(data):
sublists = [(0, len(data) - 1)]
while len(sublists) > 0:
start, end = sublists[-1]
sublists.remove((start, end))
pivot_loc = partition(data, start, end)
# If there are elements on left side of pivot,
# then add them to the stack
if pivot_loc - start > 1:
sublists.append((start, pivot_loc - 1))
# If there are elements on right side of pivot,
# then add them to the stack
if end - pivot_loc > 1:
sublists.append((pivot_loc + 1, end))
a = [5, 4, 3, 2, 1]
quick_sort(a)
print(a)
[1, 2, 4, 3, 5]
4.3.3. Recursive Implementation#
For recursive implementation, go to Section 5.6.1