Quicksort is an efficient, general-purpose
sorting algorithm
In computer science, a sorting algorithm is an algorithm that puts elements of a List (computing), list into an Total order, order. The most frequently used orders are numerical order and lexicographical order, and either ascending or descending ...
. Quicksort was developed by British computer scientist
Tony Hoare
Sir Charles Antony Richard Hoare (; born 11 January 1934), also known as C. A. R. Hoare, is a British computer scientist who has made foundational contributions to programming languages, algorithms, operating systems, formal verification, and ...
in 1959 and published in 1961.
It is still a commonly used algorithm for sorting. Overall, it is slightly faster than
merge sort
In computer science, merge sort (also commonly spelled as mergesort and as ) is an efficient, general-purpose, and comparison sort, comparison-based sorting algorithm. Most implementations of merge sort are Sorting algorithm#Stability, stable, wh ...
and
heapsort
In computer science, heapsort is an efficient, comparison-based sorting algorithm that reorganizes an input array into a heap (a data structure where each node is greater than its children) and then repeatedly removes the largest node from that ...
for randomized data, particularly on larger distributions.
Quicksort is a
divide-and-conquer algorithm
In computer science, divide and conquer is an algorithm design paradigm. A divide-and-conquer algorithm recursively breaks down a problem into two or more sub-problems of the same or related type, until these become simple enough to be solved dir ...
. It works by selecting a "pivot" element from the array and partitioning the other elements into two sub-arrays, according to whether they are less than or greater than the pivot. For this reason, it is sometimes called partition-exchange sort. The sub-arrays are then sorted
recursively
Recursion occurs when the definition of a concept or process depends on a simpler or previous version of itself. Recursion is used in a variety of disciplines ranging from linguistics to logic. The most common application of recursion is in m ...
. This can be done
in-place
In computer science, an in-place algorithm is an algorithm that operates directly on the input data structure without requiring extra space proportional to the input size. In other words, it modifies the input in place, without creating a separa ...
, requiring small additional amounts of
memory
Memory is the faculty of the mind by which data or information is encoded, stored, and retrieved when needed. It is the retention of information over time for the purpose of influencing future action. If past events could not be remembe ...
to perform the sorting.
Quicksort is a
comparison sort
A comparison sort is a type of sorting algorithm that only reads the list elements through a single abstract comparison operation (often a "less than or equal to" operator or a three-way comparison) that determines which of two elements should oc ...
, meaning that it can sort items of any type for which a "less-than" relation (formally, a
total order
In mathematics, a total order or linear order is a partial order in which any two elements are comparable. That is, a total order is a binary relation \leq on some set X, which satisfies the following for all a, b and c in X:
# a \leq a ( re ...
) is defined. It is a comparison-based sort since elements ''a'' and ''b'' are only swapped in case their relative order has been obtained in the transitive closure of prior comparison-outcomes. Most implementations of quicksort are not
stable
A stable is a building in which working animals are kept, especially horses or oxen. The building is usually divided into stalls, and may include storage for equipment and feed.
Styles
There are many different types of stables in use tod ...
, meaning that the relative order of equal sort items is not preserved.
Mathematical analysis
Analysis is the branch of mathematics dealing with continuous functions, limit (mathematics), limits, and related theories, such as Derivative, differentiation, Integral, integration, measure (mathematics), measure, infinite sequences, series ( ...
of quicksort shows that,
on average, the algorithm takes
comparisons to sort ''n'' items. In the
worst case
In computer science, best, worst, and average cases of a given algorithm express what the resource usage is ''at least'', ''at most'' and ''on average'', respectively. Usually the resource being considered is running time, i.e. time complexity, b ...
, it makes
comparisons.
History
The quicksort algorithm was developed in 1959 by
Tony Hoare
Sir Charles Antony Richard Hoare (; born 11 January 1934), also known as C. A. R. Hoare, is a British computer scientist who has made foundational contributions to programming languages, algorithms, operating systems, formal verification, and ...
while he was a visiting student at
Moscow State University
Moscow State University (MSU), officially M. V. Lomonosov Moscow State University,. is a public university, public research university in Moscow, Russia. The university includes 15 research institutes, 43 faculties, more than 300 departments, a ...
. At that time, Hoare was working on a
machine translation
Machine translation is use of computational techniques to translate text or speech from one language to another, including the contextual, idiomatic and pragmatic nuances of both languages.
Early approaches were mostly rule-based or statisti ...
project for the
National Physical Laboratory. As a part of the translation process, he needed to sort the words in Russian sentences before looking them up in a Russian-English dictionary, which was in alphabetical order on
magnetic tape
Magnetic tape is a medium for magnetic storage made of a thin, magnetizable coating on a long, narrow strip of plastic film. It was developed in Germany in 1928, based on the earlier magnetic wire recording from Denmark. Devices that use magnetic ...
. After recognizing that his first idea,
insertion sort
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time by comparisons. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. Howev ...
, would be slow, he came up with a new idea. He wrote the partition part in Mercury
Autocode
Autocode is the name of a family of "simplified coding systems", later called programming languages, devised in the 1950s and 1960s for a series of digital computers at the Universities of Manchester, Cambridge and London. Autocode was a generi ...
but had trouble dealing with the list of unsorted segments. On return to England, he was asked to write code for
Shellsort
Shellsort, also known as Shell sort or Shell's method, is an in-place algorithm, in-place comparison sort. It can be understood as either a generalization of sorting by exchange (bubble sort) or sorting by insertion (insertion sort). The method s ...
. Hoare mentioned to his boss that he knew of a faster algorithm and his boss bet a
sixpence that he did not. His boss ultimately accepted that he had lost the bet. Hoare published a paper about his algorithm in
The Computer Journal
''The Computer Journal'' is a peer-reviewed scientific journal covering computer science and information systems. Established in 1958, it is one of the oldest computer science research journals. It is published by Oxford University Press on behal ...
br>
Volume 5, Issue 1, 1962, Pages 10–16 Later, Hoare learned about
ALGOL
ALGOL (; short for "Algorithmic Language") is a family of imperative computer programming languages originally developed in 1958. ALGOL heavily influenced many other languages and was the standard method for algorithm description used by the ...
and its ability to do recursion, which enabled him to publish an improved version of the algorithm in ALGOL in ''
Communications of the Association for Computing Machinery'', the premier computer science journal of the time.
The ALGOL code is published i
Communications of the ACM (CACM), Volume 4, Issue 7 July 1961, pp 321 Algorithm 63: partition and Algorithm 64: Quicksort
Quicksort gained widespread adoption, appearing, for example, in
Unix
Unix (, ; trademarked as UNIX) is a family of multitasking, multi-user computer operating systems that derive from the original AT&T Unix, whose development started in 1969 at the Bell Labs research center by Ken Thompson, Dennis Ritchie, a ...
as the default library sort subroutine. Hence, it lent its name to the
C standard library
The C standard library, sometimes referred to as libc, is the standard library for the C (programming language), C programming language, as specified in the ISO C standard.International Organization for Standardization, ISO/International Electrote ...
subroutine
and in the reference implementation of
Java
Java is one of the Greater Sunda Islands in Indonesia. It is bordered by the Indian Ocean to the south and the Java Sea (a part of Pacific Ocean) to the north. With a population of 156.9 million people (including Madura) in mid 2024, proje ...
.
Robert Sedgewick's PhD thesis in 1975 is considered a milestone in the study of Quicksort where he resolved many open problems related to the analysis of various pivot selection schemes including
Samplesort
Samplesort is a sorting algorithm that is a divide and conquer algorithm often used in parallel processing systems. Conventional divide and conquer sorting algorithms partitions the array into sub-intervals or buckets. The buckets are then sorted i ...
, adaptive partitioning by Van Emden as well as derivation of expected number of comparisons and swaps.
Jon Bentley and
Doug McIlroy
Malcolm Douglas McIlroy (born 1932) is an American mathematician, engineer, and programmer. As of 2019 he is an Adjunct Professor of Computer Science at Dartmouth College.
McIlroy is best known for having originally proposed Unix pipelines and de ...
in 1993 incorporated various improvements for use in programming libraries, including a technique to deal with equal elements and a pivot scheme known as ''pseudomedian of nine,'' where a sample of nine elements is divided into groups of three and then the median of the three medians from three groups is chosen.
Bentley described another simpler and compact partitioning scheme in his book ''Programming Pearls'' that he attributed to
Nico Lomuto. Later Bentley wrote that he used Hoare's version for years but never really understood it but Lomuto's version was simple enough to prove correct. Bentley described Quicksort as the "most beautiful code I had ever written" in the same essay. Lomuto's partition scheme was also popularized by the textbook ''
Introduction to Algorithms
''Introduction to Algorithms'' is a book on computer programming by Thomas H. Cormen, Charles E. Leiserson, Ron Rivest, Ronald L. Rivest, and Clifford Stein. The book is described by its publisher as "the leading algorithms text in universities w ...
'' although it is inferior to Hoare's scheme because it does three times more swaps on average and degrades to runtime when all elements are equal.
McIlroy would further produce an ''AntiQuicksort'' () function in 1998, which consistently drives even his 1993 variant of Quicksort into quadratic behavior by producing adversarial data on-the-fly.
Algorithm

Quicksort is a type of
divide-and-conquer algorithm
In computer science, divide and conquer is an algorithm design paradigm. A divide-and-conquer algorithm recursively breaks down a problem into two or more sub-problems of the same or related type, until these become simple enough to be solved dir ...
for sorting an array, based on a partitioning routine; the details of this partitioning can vary somewhat, so that quicksort is really a family of closely related algorithms. Applied to a range of at least two elements, partitioning produces a division into two consecutive non empty sub-ranges, in such a way that no element of the first sub-range is greater than any element of the second sub-range. After applying this partition, quicksort then recursively sorts the sub-ranges, possibly after excluding from them an element at the point of division that is at this point known to be already in its final location. Due to its recursive nature, quicksort (like the partition routine) has to be formulated so as to be callable for a range within a larger array, even if the ultimate goal is to sort a complete array. The steps for
in-place
In computer science, an in-place algorithm is an algorithm that operates directly on the input data structure without requiring extra space proportional to the input size. In other words, it modifies the input in place, without creating a separa ...
quicksort are:
# If the range has fewer than two elements, return immediately as there is nothing to do. Possibly for other very short lengths a special-purpose sorting method is applied and the remainder of these steps skipped.
# Otherwise pick a value, called a ''pivot'', that occurs in the range (the precise manner of choosing depends on the partition routine, and can involve randomness).
# ''Partition'' the range: reorder its elements, while determining a point of division, so that all elements with values less than the pivot come before the division, while all elements with values greater than the pivot come after it; elements that are equal to the pivot can go either way. Since at least one instance of the pivot is present, most partition routines ensure that the value that ends up at the point of division is equal to the pivot, and is now in its final position (but termination of quicksort does not depend on this, as long as sub-ranges strictly smaller than the original are produced).
#
Recursively
Recursion occurs when the definition of a concept or process depends on a simpler or previous version of itself. Recursion is used in a variety of disciplines ranging from linguistics to logic. The most common application of recursion is in m ...
apply quicksort to the sub-range up to the point of division and to the sub-range after it, possibly excluding from both ranges the element equal to the pivot at the point of division. (If the partition produces a possibly larger sub-range near the boundary where all elements are known to be equal to the pivot, these can be excluded as well.)
The choice of partition routine (including the pivot selection) and other details not entirely specified above can affect the algorithm's performance, possibly to a great extent for specific input arrays. In discussing the efficiency of quicksort, it is therefore necessary to specify these choices first. Here we mention two specific partition methods.
Lomuto partition scheme
This scheme is attributed to Nico Lomuto and popularized by Bentley in his book ''Programming Pearls''
and Cormen ''et al.'' in their book ''
Introduction to Algorithms
''Introduction to Algorithms'' is a book on computer programming by Thomas H. Cormen, Charles E. Leiserson, Ron Rivest, Ronald L. Rivest, and Clifford Stein. The book is described by its publisher as "the leading algorithms text in universities w ...
''.
In most formulations this scheme chooses as the pivot the last element in the array. The algorithm maintains index as it scans the array using another index such that the elements at through (inclusive) are less than the pivot, and the elements at through (inclusive) are equal to or greater than the pivot. As this scheme is more compact and easy to understand, it is frequently used in introductory material, although it is less efficient than Hoare's original scheme e.g., when all elements are equal. The complexity of Quicksort with this scheme degrades to when the array is already in order, due to the partition being the worst possible one.
There have been various variants proposed to boost performance including various ways to select the pivot, deal with equal elements, use other sorting algorithms such as
insertion sort
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time by comparisons. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. Howev ...
for small arrays, and so on. In
pseudocode
In computer science, pseudocode is a description of the steps in an algorithm using a mix of conventions of programming languages (like assignment operator, conditional operator, loop) with informal, usually self-explanatory, notation of actio ...
, a quicksort that sorts elements at through (inclusive) of an array can be expressed as:
''// Sorts (a portion of) an array, divides it into partitions, then sorts those''
algorithm quicksort(A, lo, hi) is
''// Ensure indices are in correct order''
if lo >= hi , , lo < 0 then
return
''// Partition array and get the pivot index''
p := partition(A, lo, hi)
''// Sort the two partitions''
quicksort(A, lo, p - 1) ''// Left side of pivot''
quicksort(A, p + 1, hi) ''// Right side of pivot''
''// Divides array into two partitions''
algorithm partition(A, lo, hi) is
pivot := A
i''// Choose the last element as the pivot''
''// Temporary pivot index''
i := lo
for j := lo to hi - 1 do
''// If the current element is less than or equal to the pivot''
if A
<= pivot then
''// Swap the current element with the element at the temporary pivot index''
swap A
with A
''// Move the temporary pivot index forward''
i := i + 1
''// Swap the pivot with the last element''
swap A
with A
i return i ''// the pivot index''
Sorting the entire array is accomplished by .
Hoare partition scheme

The original partition scheme described by
Tony Hoare
Sir Charles Antony Richard Hoare (; born 11 January 1934), also known as C. A. R. Hoare, is a British computer scientist who has made foundational contributions to programming languages, algorithms, operating systems, formal verification, and ...
uses two pointers (indices into the range) that start at both ends of the array being partitioned, then move toward each other, until they detect an inversion: a pair of elements, one greater than the pivot at the first pointer, and one less than the pivot at the second pointer; if at this point the first pointer is still before the second, these elements are in the wrong order relative to each other, and they are then exchanged. After this the pointers are moved inwards, and the search for an inversion is repeated; when eventually the pointers cross (the first points after the second), no exchange is performed; a valid partition is found, with the point of division between the crossed pointers (any entries that might be strictly between the crossed pointers are equal to the pivot and can be excluded from both sub-ranges formed). With this formulation it is possible that one sub-range turns out to be the whole original range, which would prevent the algorithm from advancing. Hoare therefore stipulates that at the end, the sub-range containing the pivot element (which still is at its original position) can be decreased in size by excluding that pivot, after (if necessary) exchanging it with the sub-range element closest to the separation; thus, termination of quicksort is ensured.
With respect to this original description, implementations often make minor but important variations. Notably, the scheme as presented below includes elements equal to the pivot among the candidates for an inversion (so "greater than or equal" and "less than or equal" tests are used instead of "greater than" and "less than" respectively; since the formulation uses rather than which is actually reflected by the use of strict comparison operators). While there is no reason to exchange elements equal to the pivot, this change allows tests on the pointers themselves to be omitted, which are otherwise needed to ensure they do not run out of range. Indeed, since at least one instance of the pivot value is present in the range, the first advancement of either pointer cannot pass across this instance if an inclusive test is used; once an exchange is performed, these exchanged elements are now both strictly ahead of the pointer that found them, preventing that pointer from running off. (The latter is true independently of the test used, so it would be possible to use the inclusive test only when looking for the first inversion. However, using an inclusive test throughout also ensures that a division near the middle is found when all elements in the range are equal, which gives an important efficiency gain for sorting arrays with many equal elements.) The risk of producing a non-advancing separation is avoided in a different manner than described by Hoare. Such a separation can only result when no inversions are found, with both pointers advancing to the pivot element at the first iteration (they are then considered to have crossed, and no exchange takes place).
In
pseudocode
In computer science, pseudocode is a description of the steps in an algorithm using a mix of conventions of programming languages (like assignment operator, conditional operator, loop) with informal, usually self-explanatory, notation of actio ...
,
''// Sorts (a portion of) an array, divides it into partitions, then sorts those''
algorithm quicksort(A, lo, hi) is
if lo >= 0 && hi >= 0 && lo < hi then
p := partition(A, lo, hi)
quicksort(A, lo, p) // Note: the pivot is now included
quicksort(A, p + 1, hi)
''// Divides array into two partitions''
algorithm partition(A, lo, hi) is
''// Pivot value''
pivot := A
o''// Choose the first element as the pivot''
''// Left index''
i := lo - 1
''// Right index''
j := hi + 1
loop forever
''// Move the left index to the right at least once and while the element at''
''// the left index is less than the pivot''
do i := i + 1 while A
< pivot
''// Move the right index to the left at least once and while the element at''
''// the right index is greater than the pivot''
do j := j - 1 while A
> pivot
''// If the indices crossed, return''
if i >= j then return j
''// Swap the elements at the left and right indices''
swap A
with A
The entire array is sorted by .
Hoare's scheme is more efficient than Lomuto's partition scheme because it does three times fewer swaps on average. Also, as mentioned, the implementation given creates a balanced partition even when all values are equal.
, which Lomuto's scheme does not. Like Lomuto's partition scheme, Hoare's partitioning also would cause Quicksort to degrade to for already sorted input, if the pivot was chosen as the first or the last element. With the middle element as the pivot, however, sorted data results with (almost) no swaps in equally sized partitions leading to best case behavior of Quicksort, i.e. . Like others, Hoare's partitioning doesn't produce a stable sort. In this scheme, the pivot's final location is not necessarily at the index that is returned, as the pivot and elements equal to the pivot can end up anywhere within the partition after a partition step, and may not be sorted until the base case of a partition with a single element is reached via recursion. Therefore, the next two segments that the main algorithm recurs on are (elements ≤ pivot) and (elements ≥ pivot) as opposed to and as in Lomuto's scheme.
Subsequent recursions (expansion on previous paragraph)
Let's expand a little bit on the next two segments that the main algorithm recurs on. Because we are using strict comparators (>, <) in the loops to prevent ourselves from running out of range, there's a chance that the pivot itself gets swapped with other elements in the partition function. Therefore, the index returned in the partition function isn't necessarily where the actual pivot is. Consider the example of , following the scheme, after the first partition the array becomes , the "index" returned is 2, which is the number 1, when the real pivot, the one we chose to start the partition with was the number 3. With this example, we see how it is necessary to include the returned index of the partition function in our subsequent recursions. As a result, we are presented with the choices of either recursing on and , or and . Which of the two options we choose depends on which index (i or j) we return in the partition function when the indices cross, and how we choose our pivot in the partition function (floor v.s. ceiling).
First examine the choice of recursing on and , with the example of sorting an array where multiple identical elements exist . If index i (the "latter" index) is returned after indices cross in the partition function, the index 1 would be returned after the first partition. The subsequent recursion on would be on (0, 1), which corresponds to the exact same array . A non-advancing separation that causes infinite recursion is produced. It is therefore obvious that when recursing on and , because the left half of the recursion includes the returned index, it is the partition function's job to exclude the "tail" in non-advancing scenarios. Which is to say, index j (the "former" index when indices cross) should be returned instead of i. Going with a similar logic, when considering the example of an already sorted array , the choice of pivot needs to be "floor" to ensure that the pointers stop on the "former" instead of the "latter" (with "ceiling" as the pivot, the index 1 would be returned and included in causing infinite recursion). It is for the exact same reason why choice of the last element as pivot must be avoided.
The choice of recursing on and follows the exact same logic as above. Because the right half of the recursion includes the returned index, it is the partition function's job to exclude the "head" in non-advancing scenarios. The index i (the "latter" index after the indices cross) in the partition function needs to be returned, and "ceiling" needs to be chosen as the pivot. The two nuances are clear, again, when considering the examples of sorting an array where multiple identical elements exist (), and an already sorted array respectively. It is noteworthy that with version of recursion, for the same reason, choice of the first element as pivot must be avoided.
Implementation issues
Choice of pivot
In the very early versions of quicksort, the leftmost element of the partition would often be chosen as the pivot element. Unfortunately, this causes worst-case behavior on already sorted arrays, which is a rather common use-case. The problem was easily solved by choosing either a random index for the pivot, choosing the middle index of the partition or (especially for longer partitions) choosing the
median
The median of a set of numbers is the value separating the higher half from the lower half of a Sample (statistics), data sample, a statistical population, population, or a probability distribution. For a data set, it may be thought of as the “ ...
of the first, middle and last element of the partition for the pivot (as recommended by
Sedgewick).
This "median-of-three" rule counters the case of sorted (or reverse-sorted) input, and gives a better estimate of the optimal pivot (the true median) than selecting any single element, when no information about the ordering of the input is known.
Median-of-three code snippet for Lomuto partition:
mid := ⌊(lo + hi) / 2⌋
if A
id< A
o swap A
owith A
id if A
i< A
o swap A
owith A
i if A
id< A
i swap A
idwith A
i pivot := A
iIt puts a median into
A i/code> first, then that new value of A i/code> is used for a pivot, as in a basic algorithm presented above.
Specifically, the expected number of comparisons needed to sort elements (see ) with random pivot selection is . Median-of-three pivoting brings this down to , at the expense of a three-percent increase in the expected number of swaps. An even stronger pivoting rule, for larger arrays, is to pick the ninther, a recursive median-of-three (Mo3), defined as
:
Selecting a pivot element is also complicated by the existence of integer overflow
In computer programming, an integer overflow occurs when an arithmetic operation on integers attempts to create a numeric value that is outside of the range that can be represented with a given number of digits – either higher than the maximu ...
. If the boundary indices of the subarray being sorted are sufficiently large, the naïve expression for the middle index, , will cause overflow and provide an invalid pivot index. This can be overcome by using, for example, to index the middle element, at the cost of more complex arithmetic. Similar issues arise in some other methods of selecting the pivot element.
Repeated elements
With a partitioning algorithm such as the Lomuto partition scheme described above (even one that chooses good pivot values), quicksort exhibits poor performance for inputs that contain many repeated elements. The problem is clearly apparent when all the input elements are equal: at each recursion, the left partition is empty (no input values are less than the pivot), and the right partition has only decreased by one element (the pivot is removed). Consequently, the Lomuto partition scheme takes quadratic time
In theoretical computer science, the time complexity is the computational complexity that describes the amount of computer time it takes to run an algorithm. Time complexity is commonly estimated by counting the number of elementary operations p ...
to sort an array of equal values. However, with a partitioning algorithm such as the Hoare partition scheme, repeated elements generally results in better partitioning, and although needless swaps of elements equal to the pivot may occur, the running time generally decreases as the number of repeated elements increases (with memory cache reducing the swap overhead). In the case where all elements are equal, Hoare partition scheme needlessly swaps elements, but the partitioning itself is best case, as noted in the Hoare partition section above.
To solve the Lomuto partition scheme problem (sometimes called the Dutch national flag problem
The Dutch national flag problem is a computational problem proposed by Edsger Dijkstra.In a chapter of his book ''A Discipline of Programming'' Prentice-Hall, 1976 The flag of the Netherlands consists of three colors: red, white, and blue. Given ...
), an alternative linear-time partition routine can be used that separates the values into three groups: values less than the pivot, values equal to the pivot, and values greater than the pivot. (Bentley and McIlroy call this a "fat partition" and it was already implemented in the of Version 7 Unix
Version 7 Unix, also called Seventh Edition Unix, Version 7 or just V7, was an important early release of the Unix operating system. V7, released in 1979, was the last Bell Laboratories release to see widespread distribution before the commerc ...
.) The values equal to the pivot are already sorted, so only the less-than and greater-than partitions need to be recursively sorted. In pseudocode, the quicksort algorithm becomes:
''// Sorts (a portion of) an array, divides it into partitions, then sorts those''
algorithm quicksort(A, lo, hi) is
if lo >= 0 && lo < hi then
lt, gt := partition(A, lo, hi) ''// Multiple return values''
quicksort(A, lo, lt - 1)
quicksort(A, gt + 1, hi)
''// Divides array into three partitions''
algorithm partition(A, lo, hi) is
''// Pivot value''
pivot := A lo + hi) / 2''// Choose the middle element as the pivot (integer division)''
''// Lesser, equal and greater index''
lt := lo
eq := lo
gt := hi
''// Iterate and compare all elements with the pivot''
while eq <= gt do
if A q< pivot then
''// Swap the elements at the equal and lesser indices''
swap A qwith A t ''// Increase lesser index''
lt := lt + 1
''// Increase equal index''
eq := eq + 1
else if A q> pivot then
''// Swap the elements at the equal and greater indices''
swap A qwith A t ''// Decrease greater index''
gt := gt - 1
else ''// if A q= pivot then''
''// Increase equal index''
eq := eq + 1
''// Return lesser and greater indices''
return lt, gt
The partition
algorithm returns indices to the first ('leftmost') and to the last ('rightmost') item of the middle partition. Every other item of the partition is equal to the pivot and is therefore sorted. Consequently, the items of the partition need not be included in the recursive calls to quicksort
.
The best case for the algorithm now occurs when all elements are equal (or are chosen from a small set of elements). In the case of all equal elements, the modified quicksort will perform only two recursive calls on empty subarrays and thus finish in linear time (assuming the partition
subroutine takes no longer than linear time).
Optimizations
Other important optimizations, also suggested by Sedgewick and widely used in practice, are:[qsort.c in ]GNU libc
The GNU C Library, commonly known as glibc, is the GNU Project implementation of the C standard library. It provides a wrapper around the system calls of the Linux kernel and other kernels for application use. Despite its name, it now also dir ...
/ref>
* To make sure at most space is used, wikt:recurse, recur first into the smaller side of the partition, then use a tail call
In computer science, a tail call is a subroutine call performed as the final action of a procedure. If the target of a tail is the same subroutine, the subroutine is said to be tail recursive, which is a special case of direct recursion. Tail recur ...
to recur into the other, or update the parameters to no longer include the now sorted smaller side, and iterate to sort the larger side.
* When the number of elements is below some threshold (perhaps ten elements), switch to a non-recursive sorting algorithm such as insertion sort
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time by comparisons. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. Howev ...
that performs fewer swaps, comparisons or other operations on such small arrays. The ideal 'threshold' will vary based on the details of the specific implementation.
* An older variant of the previous optimization: when the number of elements is less than the threshold , simply stop; then after the whole array has been processed, perform insertion sort on it. Stopping the recursion early leaves the array -sorted, meaning that each element is at most positions away from its final sorted position. In this case, insertion sort takes time to finish the sort, which is linear if is a constant. Compared to the "many small sorts" optimization, this version may execute fewer instructions, but it makes suboptimal use of the cache memories in modern computers.
Parallelization
Quicksort's divide-and-conquer formulation makes it amenable to parallelization
Parallel computing is a type of computation in which many calculations or processes are carried out simultaneously. Large problems can often be divided into smaller ones, which can then be solved at the same time. There are several different for ...
using task parallelism
Task parallelism (also known as function parallelism and control parallelism) is a form of parallelization of computer code across multiple processors in parallel computing environments. Task parallelism focuses on distributing tasks—concurre ...
. The partitioning step is accomplished through the use of a parallel prefix sum algorithm to compute an index for each array element in its section of the partitioned array. Given an array of size , the partitioning step performs work in time and requires additional scratch space. After the array has been partitioned, the two partitions can be sorted recursively in parallel. Assuming an ideal choice of pivots, parallel quicksort sorts an array of size in work in time using additional space.
Quicksort has some disadvantages when compared to alternative sorting algorithms, like merge sort
In computer science, merge sort (also commonly spelled as mergesort and as ) is an efficient, general-purpose, and comparison sort, comparison-based sorting algorithm. Most implementations of merge sort are Sorting algorithm#Stability, stable, wh ...
, which complicate its efficient parallelization. The depth of quicksort's divide-and-conquer tree directly impacts the algorithm's scalability, and this depth is highly dependent on the algorithm's choice of pivot. Additionally, it is difficult to parallelize the partitioning step efficiently in-place. The use of scratch space simplifies the partitioning step, but increases the algorithm's memory footprint and constant overheads.
Other more sophisticated parallel sorting algorithms can achieve even better time bounds. For example, in 1991 David M W Powers
David (; , "beloved one") was a king of ancient Israel and Judah and the third king of the United Monarchy, according to the Hebrew Bible and Old Testament.
The Tel Dan stele, an Aramaic-inscribed stone erected by a king of Aram-Damas ...
described a parallelized quicksort (and a related radix sort
In computer science, radix sort is a non-comparative sorting algorithm. It avoids comparison by creating and distributing elements into buckets according to their radix. For elements with more than one significant digit, this bucketing process i ...
) that can operate in time on a CRCW (concurrent read and concurrent write) PRAM (parallel random-access machine) with processors by performing partitioning implicitly.
Formal analysis
Worst-case analysis
The most unbalanced partition occurs when one of the sublists returned by the partitioning routine is of size .[The other one may either have element or be empty (have elements), depending on whether the pivot is included in one of subpartitions, as in the Hoare's partitioning routine, or is excluded from both of them, like in the Lomuto's routine.] This may occur if the pivot happens to be the smallest or largest element in the list, or in some implementations (e.g., the Lomuto partition scheme as described above) when all the elements are equal.
If this happens repeatedly in every partition, then each recursive call processes a list of size one less than the previous list. Consequently, it takes nested calls before to reach a list of size 1. This means that the call tree is a linear chain of nested calls. The th call does work to do the partition, and , so in that case quicksort takes time.
Best-case analysis
In the most balanced case, each partition divides the list into two nearly equal pieces. This means each recursive call processes a list of half the size. Consequently, only nested calls can be made before reaching a list of size 1. This means that the depth of the call tree is . But no two calls at the same level of the call tree process the same part of the original list; thus, each level of calls needs only time all together (each call has some constant overhead, but since there are only calls at each level, this is subsumed in the factor). The result is that the algorithm uses only time.
Average-case analysis
To sort an array of distinct elements, quicksort takes time in expectation, averaged over all permutations of elements with equal probability. Alternatively, if the algorithm selects the pivot uniformly at random from the input array, the same analysis can be used to bound the expected running time for any input sequence; the expectation is then taken over the random choices made by the algorithm (Cormen ''et al.'', ''Introduction to Algorithms
''Introduction to Algorithms'' is a book on computer programming by Thomas H. Cormen, Charles E. Leiserson, Ron Rivest, Ronald L. Rivest, and Clifford Stein. The book is described by its publisher as "the leading algorithms text in universities w ...
'', Section 7.3).
Three common proofs to this claim use percentiles, recurrences, and binary search trees, each providing different insights into quicksort's workings.
Using percentiles
If each pivot has rank somewhere in the middle 50 percent, that is, between the 25th percentile
In statistics, a ''k''-th percentile, also known as percentile score or centile, is a score (e.g., a data point) a given percentage ''k'' of all scores in its frequency distribution exists ("exclusive" definition) or a score a given percentage ...
and the 75th percentile, then it splits the elements with at least 25% and at most 75% on each side. Consistently choosing such pivots would only have to split the list at most times before reaching lists of size 1, yielding an algorithm.
When the input is a random permutation, the pivot has a random rank, and so it is not guaranteed to be in the middle 50 percent. However, when starting from a random permutation, each recursive call's pivot has a random rank in its list, and therefore is in the middle 50 percent approximately half the time. Imagine that a coin is flipped: heads means that the rank of the pivot is in the middle 50 percent, tail means that it isn't. Now imagine that the coin is flipped over and over until it gets heads. Although this could take a long time, on average only flips are required, and the chance that the coin won't get heads after flips is highly improbable (this can be made rigorous using Chernoff bound
In probability theory, a Chernoff bound is an exponentially decreasing upper bound on the tail of a random variable based on its moment generating function. The minimum of all such exponential bounds forms ''the'' Chernoff or Chernoff-Cramér boun ...
s). By the same argument, Quicksort's recursion will terminate on average at a call depth of only . But if its average call depth is , and each level of the call tree processes at most elements, the total amount of work done on average is the product, . The algorithm does not have to verify that the pivot is in the middle half as long as it is a consistent amount of times.
Using recurrences
An alternative approach is to set up a recurrence relation
In mathematics, a recurrence relation is an equation according to which the nth term of a sequence of numbers is equal to some combination of the previous terms. Often, only k previous terms of the sequence appear in the equation, for a parameter ...
for the factor, the time needed to sort a list of size . In the most unbalanced case, a single quicksort call involves work plus two recursive calls on lists of size and , so the recurrence relation is
:
This is the same relation as for insertion sort
Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time by comparisons. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. Howev ...
and selection sort
In computer science, selection sort is an in-place comparison sorting algorithm. It has a O(''n''2) time complexity, which makes it inefficient on large lists, and generally performs worse than the similar insertion sort. Selection sort is note ...
, and it solves to worst case .
In the most balanced case, a single quicksort call involves work plus two recursive calls on lists of size , so the recurrence relation is
:
The master theorem for divide-and-conquer recurrences tells us that .
The outline of a formal proof of the expected time complexity follows. Assume that there are no duplicates as duplicates could be handled with linear time pre- and post-processing, or considered cases easier than the analyzed. When the input is a random permutation, the rank of the pivot is uniform random from 0 to . Then the resulting parts of the partition have sizes and , and i is uniform random from 0 to . So, averaging over all possible splits and noting that the number of comparisons for the partition is , the average number of comparisons over all permutations of the input sequence can be estimated accurately by solving the recurrence relation:
:
:
:
:
:
Solving the recurrence gives .
This means that, on average, quicksort performs only about 39% worse than in its best case. In this sense, it is closer to the best case than the worst case. A comparison sort
A comparison sort is a type of sorting algorithm that only reads the list elements through a single abstract comparison operation (often a "less than or equal to" operator or a three-way comparison) that determines which of two elements should oc ...
cannot use less than comparisons on average to sort items (as explained in the article Comparison sort) and in case of large , Stirling's approximation
In mathematics, Stirling's approximation (or Stirling's formula) is an asymptotic approximation for factorials. It is a good approximation, leading to accurate results even for small values of n. It is named after James Stirling, though a related ...
yields , so quicksort is not much worse than an ideal comparison sort. This fast average runtime is another reason for quicksort's practical dominance over other sorting algorithms.
Using a binary search tree
The following binary search tree
In computer science, a binary search tree (BST), also called an ordered or sorted binary tree, is a Rooted tree, rooted binary tree data structure with the key of each internal node being greater than all the keys in the respective node's left ...
(BST) corresponds to each execution of quicksort: the initial pivot is the root node; the pivot of the left half is the root of the left subtree, the pivot of the right half is the root of the right subtree, and so on. The number of comparisons of the execution of quicksort equals the number of comparisons during the construction of the BST by a sequence of insertions. So, the average number of comparisons for randomized quicksort equals the average cost of constructing a BST when the values inserted form a random permutation.
Consider a BST created by insertion of a sequence of values forming a random permutation. Let denote the cost of creation of the BST. We have , where is a binary random variable expressing whether during the insertion of there was a comparison to .
By linearity of expectation
In probability theory, the expected value (also called expectation, expectancy, expectation operator, mathematical expectation, mean, expectation value, or first moment) is a generalization of the weighted average. Informally, the expected va ...
, the expected value