Quicksort Quicksort is a divide and conquer algorithm. Quicksort first divides a large list into two smaller sub-lists: the low elements and the high elements. Quicksort can then recursively sort the sub-lists. Quicksort is one of the most common sorting algorithms for sequential computers because of its simplicity, low overhead, and optimal average complexity. Quicksort selects one of the entries in the sequence to be the pivot and divides the sequence into two - one with all elements less than or equal to pivot are placed before the pivot and elements greater than pivot are placed after the pivot. The process is recursively applied to each of the sublists. Quicksort operates in O(N*logN) time. The base case of the recursion is list of size zero or one, which never need to be sorted. Quicksort consists of two phases: - Sort phase. - Partition phase. Algorithm The divide-and-conquer strategy is used in quicksort. Below the recursion step is described: 1. Choose a pivot value. We take the value of the middle element as pivot value, but it can be any value, which is in range of sorted values, even if it doesn't present in the array. 2. Partition. Rearrange elements in such a way, that all elements which are lesser than the pivot go to the left part of the array and all elements greater than the pivot, go to the right part of the array. Values equal to the pivot can stay in any part of the array. Notice, that array may be divided in non-equal parts. 3. Sort both parts. Apply quicksort algorithm recursively to the left and the right parts.
Partition algorithm in detail There are two indices i and j and at the very beginning of the partition algorithm i points to the first element in the array and j points to the last one. Then algorithm moves i forward, until an element with value greater or equal to the pivot is found. Index j is moved backward, until an element with value lesser or equal to the pivot is found. If i j then they are swapped and i steps to the next position (i + 1), j steps to the previous one (j - 1). Algorithm stops, when i becomes greater than j. After partition, all values before i-th element are less or equal than the pivot and all values after j-th element are greater or equal to the pivot.
Example. Sort {1, 12, 5, 26, 7, 14, 3, 7, 2 using quicksort. Notice, that we show here only the first recursion step, in order not to make example too long. But, in fact, {1, 2, 5, 7, 3 and {14, 7, 26, 12 are sorted then recursively.
void quicksort(int arr[], int left, int right) { int i = left, j = right; int tmp; int pivot = arr[(left + right) / 2]; /* partition */ while (i <= j) { while (arr[i] < pivot) i++; while (arr[j] > pivot) j--; if (i <= j) { tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i++; j--; ; /* recursion */ if (left < j) quicksort(arr, left, j); if (i < right) quicksort(arr, i, right);
void QuickSort(DataType data[ ], int n) { int pivot_index; int n1; int n2; // Array index for the pivot element // Number of elements before pivot element // Number of elements after pivot element if (n>1) { // Partition array and set pivot index partition(data, n, pivot_index); // Sizes of subarrays n1 = pivot_index; n2 = n n1 1; // Recursively, sort the subarrays quicksort(data,n1); quicksort(data+n1+1, n2);
Partition Function
The Partition Function // Pre: data array has n >= 2 elements // Post: pivot element is selected // array elements are rearranged such that // data[pivot_index] = pivot // data[i] <= pivot when i < pivot_index // data[i] > pivot when i > pivot_index void partition(datatype data[], int n, int& pivot_index) { DataType pivot = data[0]; // Pivot is picked at index 0 int i = 0; // Index to be incremented int j = n; // Index to be decremented while (i < j) { do j-- while (data[j] > pivot); do i++ while (i < j && data[i] <= pivot); if (i < j) swap(data[i],data[j]); pivot_index = j; swap(data[0],data[pivot_index]);
Analysis of Quicksort Partitioning an array of n elements is O(n) In the best and average cases: Partition function places pivot somewhere in the middle Number of levels is O(log2n), Running time is O(n log2n) In the worst case, an array is initially sorted or reverse sorted Partition function places pivot at the beginning or end Number of levels is O(n), Running time is O(n 2 ) Advantages: One of the fastest algorithms on average Does not need additional memory (the sorting takes place in the array - this is called in-place processing ) Disadvantages: The worst-case complexity is O(N 2 )