Anne Dawson: Quicksort.htm  

Last updated: Saturday 4th August 2007, 6:53 PT

 

Please report any errors or omissions in this document:

anne.dawson@gmail.com

 

 

Quicksort

 

The Quicksort sorting algorithm was created in 1960 by British computer scientist Tony Hoare - currently Professor of Computer Science at Oxford University in England. Quicksort has a best case running time of O(NLogN), an average case running time of O(NLogN) and a worst case running time of O(N2).

This document explains how the Quicksort algorithm sorts by illustrating a sort on an array of ten integers into ascending order.

 

Quicksort works by dividing the array into two subarrays whereby all the values in one subarray are greater than all the values in the other subarray. This subdivision process is known as partitioning. The algorithm then recursively calls itself to partition each subarray into two more subarrays. This recursion continues until the array is completely sorted.

 

The Quicksort algorithm

 

Note: low and high refer to the limits of the array.

 

void Quicksort (int array[], int low, int high)

{

IF there are 0 or 1 element to sort

return;

IF there are two elements to sort THEN

if necessary, swap array[low] and array[high]

ELSE

{

rearrange (i.e. partition) the array so that

all values in array[low .. marker -1] are less than

all values in array[marker .. high]

Quicksort(array, low, marker - 1);

Quicksort(array, marker, high);

}

}

 

 

 

Quicksort performs best if it can partition the array into two subarrays of exactly half the size of the original. The following diagram shows the partitioning of an array of size 16 for the best case of Quicksort:

 

 

 

 

 

Quicksort performs best if it can partition the array into two subarrays of exactly half the size of the original. In this case, each recursive call reduces the size of the data to be sorted by a half. The figure above illustrates the best case scenario. In general, the best case number of recursive calls is O(N) and the best case array size per recursive call is O(LogN).

 

 

 

Performance

 

The run-time performance of the Quicksort algorithm depends upon the number of recursive function calls multiplied by the time spent executing each function call. Other than calling itself recursively, a single function call spends most of its time partitioning the data into subarrays. Partitioning the array depends on N, but the average size of the array (in the best case) is LogN. The Quicksort running time can thus be estimated as follows:

 

Quicksort time = number of function calls * time for one partitioning

= O(N) * O(LogN)

= O(N * LogN)

= O(N log N)

 

 

 

The Partitioning Algorithm

 

The partitioning method starts by selecting one element of the array as a pivot, the value against which all other elements of the array are compared. The choice of pivot can drastically affect the performance of the algorithm. In this algorithm, the pivot is the first element of the array, and the values are sorted into ascending order.

 

 

pivot = array[low];

lowSwap = low + 1;

highSwap = high;

do

{

Scan forward from lowSwap until encountering a value > pivot

and set lowSwap to index this value

 

Scan backwards from highSwap until encountering a value <= pivot

            and set highSwap to index this value

 

IF lowSwap and highSwap did not cross THEN

swap array[lowSwap] and array[highSwap]

 

} while (lowSwap and highSwap have not crossed);

swap the pivot (array[low])

with the element where lowSwap and highSwap crossed

 

 

 

Consider the following example:

 

The array to be sorted has ten elements:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Animation of the above algorithm:

http://www.site.uottawa.ca/~stan/csi2514/applets/sort/sort.html

 

Click on the button,

then click on the down arrow besides the word Bubble Sort,

then select QuickSort, then click on the Go button.