Quick Sort
Introduction
The Quicksort algorithm is a fast non-stable sorting
algorithm, which applies the divide and conquer concept. Non-stable means that
the order of elements with the same sorting key is not necessarily maintained.
It was developed around 1960 by Antony R. Hoare and has been
improved several times since then.
The Quicksort algorithm has an average runtime of $O(n \log n)$ and a
worst-case runtime of $O(n^2)$. In the worst case, the Quicksort algorithm has
space complexity of $O(n)$.
Functionality
The Quicksort algorithm splits a list into two sublists ensuring that one
sublist contains only elements smaller than a chosen pivot and the other sublist
contains only elements larger than the pivot. This process is repeated on the
two sublists until the entire list is sorted.
This follows these instructions:
- If the list contains less than two elements, return directly as there is nothing to do, a list with only one or less element is always sorted.
- If this isn’t the case choose an element from the list as the
pivot. The method by which thepivotis chosen can vary depending on the implementation. - Now the list needs to be partitioned, for this a point of partition is chosen and all elements smaller than the pivot are placed in one sublist and all elements larger in the other. It can make sense to choose the pivot as the center point between the two sublists, as it will already be in the correct position and doesn’t need to be sorted further.
- Now this process can be repeated recursively on both sublists until the list is sorted.
Example
To illustrate the Quicksort algorithm, consider the following example, given
is the following list:
$$ \boxed{3} \quad \boxed{1} \quad \boxed{4} \quad \boxed{1} \quad \boxed{5} \quad \boxed{9} \quad \boxed{2} \quad \boxed{6} \quad \boxed{5} \quad \boxed{3} $$
As this list contains more than one element we need to choose a pivot. In this
example I simply choose the last value of the list, so 3.
$$ \boxed{3} \quad \boxed{1} \quad \boxed{4} \quad \boxed{1} \quad \boxed{5} \quad \boxed{9} \quad \boxed{2} \quad \boxed{6} \quad \boxed{5} \quad \color{red}{\boxed{3}} $$
Now that we have a pivot we can ensure that all elements smaller than the
pivot are on the left side of the list and all elements larger than the
pivot are on the right side
For this we start on the left side of the list and search for an element which
isn’t smaller than the pivot. This will be the first element 3.
$$ {\color{blue}{\boxed{3}}} \quad \boxed{1} \quad \boxed{4} \quad \boxed{1} \quad \boxed{5} \quad \boxed{9} \quad \boxed{2} \quad \boxed{6} \quad \boxed{5} \quad {\color{red}{\boxed{3}}} $$
Now we do the same thing starting from the right side and search for the first
element that isn’t larger than the pivot. On the first search this will always
be the pivot.
$$ {\color{blue}{\boxed{3}}} \quad \boxed{1} \quad \boxed{4} \quad \boxed{1} \quad \boxed{5} \quad \boxed{9} \quad \boxed{2} \quad \boxed{6} \quad \boxed{5} \quad {\color{green}{\boxed{3}}} $$
Now both elements get swapped, this process of searching from the left and right and the swapping the two elements continues until the two searches meet. For our list this looks like this.
$$ \boxed{3} \quad \boxed{1} \quad {\color{blue}{\boxed{4}}} \quad \boxed{1} \quad \boxed{5} \quad \boxed{9} \quad {\color{green}{\boxed{2}}} \quad \boxed{6} \quad \boxed{5} \quad \boxed{3} $$
$$ \boxed{3} \quad \boxed{1} \quad {\color{green}{\boxed{2}}} \quad \boxed{1} \quad \boxed{5} \quad \boxed{9} \quad {\color{blue}{\boxed{4}}} \quad \boxed{6} \quad \boxed{5} \quad \boxed{3} $$
$$ \boxed{3} \quad \boxed{1} \quad \boxed{2} \quad {\color{green}{\boxed{1}}} \quad {\color{blue}{\boxed{5}}} \quad \boxed{9} \quad \boxed{4} \quad \boxed{6} \quad \boxed{5} \quad \boxed{3} $$
Now that the two searches have met each other we can partition out list into two
parts. The left part contains all elements up to the 1 which was found by the
right search and the right half contains the rest.
$$ \boxed{3} \quad \boxed{1} \quad \boxed{2} \quad \boxed{1} \quad \mid \quad \boxed{5} \quad \boxed{9} \quad \boxed{4} \quad \boxed{6} \quad \boxed{5} \quad \boxed{3} $$
Now we can repeat the process on both parts of the list until it is sorted. For simplicity I will only show the left part of the list.
$$ {\color{blue}{\boxed{3}}} \quad \boxed{1} \quad \boxed{2} \quad {\color{green}{\boxed{1}}} $$
$$ {\color{green}{\boxed{1}}} \quad \boxed{1} \quad \boxed{2} \quad {\color{blue}{\boxed{3}}} $$
$$ {\color{green}{\boxed{1}}} \quad {\color{blue}{\boxed{1}}} \quad \boxed{2} \quad \boxed{3} $$
$$ \boxed{1} \quad \mid \quad \boxed{1} \quad \boxed{2} \quad \boxed{3} $$
Now that we only have one element left this part of the list is sorted.
$$ \boxed{1} $$
After the remaining parts of the list are sorted the complete list looks like this:
$$ \boxed{1} \quad \boxed{1} \quad \boxed{2} \quad \boxed{3} \quad \boxed{3} \quad \boxed{4} \quad \boxed{5} \quad \boxed{5} \quad \boxed{6} \quad \boxed{9} $$
Pseudocode
To define the algorithm, we can use the following pseudocode:
function quicksort(arr, low, high) {
// Stop out of bounds access
if (low < 0 || low >= list.size() || high < 0 || high >= list.size()) {
return;
}
if (low < high) {
pivot = partition(arr, low, high);
quicksort(arr, low, pivot);
quicksort(arr, pivot + 1, high)
}
}
function partition(arr, low, high) {
pivot = arr[high];
i = low - 1;
j = high + 1;
for(;;) {
do { i++; } while (arr[i] < pivot);
do { j--; } while (arr[j] > pivot);
if (i >= j) {
return j;
}
swap(arr[i], arr[j]);
}
}
quicksort(list, 0, list.size() - 1);
Resources
Quicksort - Wikipedia Quicksort - Geeks for Geeks
Impllementations
Implementation in C++
#include <bits/stdc++.h>
#include <iostream>
#include <utility>
#include <vector>
int partition(std::vector<int> &arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
std::swap(arr[i], arr[j]);
}
}
// Move the pivot to the position between both list parts.
// This puts the pivot in the correct position, allowing it
// to be excluded from the next recursive calls.
std::swap(arr[i + 1], arr[high]);
return i + 1;
}
void quicksort(std::vector<int> &arr, int low, int high) {
if (low < 0 || low >= arr.size() || high < 0 || high >= arr.size()) {
return;
}
if (low < high) {
int pivot = partition(arr, low, high);
quicksort(arr, low, pivot - 1);
quicksort(arr, pivot + 1, high);
}
}
int main() {
std::vector<int> list = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
quicksort(list, 0, list.size() - 1);
for (const auto &i : list) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
Last updated 20 Jun 2025, 10:57 +0200 .
What did you like?
What went wrong?