Quick Sort is a widely used Divide and Conquer sorting algorithm that is very efficient for large datasets. It works by selecting a "pivot" element from the array and partitioning the other elements into two subarrays, according to whether they are smaller or greater than the pivot. The algorithm then recursively sorts the subarrays. Quick Sort is efficient in practice and is often faster than other O(n log n) algorithms like Merge Sort and Heap Sort due to its smaller hidden constants.
Quick Sort follows these basic steps:
Pick a Pivot: Select an element from the array to act as a pivot. Different pivot selection strategies exist (e.g., pick the first element, last element, middle element, or a random element).
Partitioning: Re-arrange the array so that:
Recursively Sort Subarrays: Recursively apply the Quick Sort algorithm to the two subarrays (left and right of the pivot) until the entire array is sorted.
Here is the pseudocode for Quick Sort:
// Function to perform partitioning
int partition(int arr[], int low, int high) {
// Pivot is selected as the last element of the array
int pivot = arr[high];
int i = (low - 1); // Index of smaller element
// Traverse through all elements of the array
for (int j = low; j <= high - 1; j++) {
if (arr[j] < pivot) {
i++; // Increment index of smaller element
swap(arr[i], arr[j]); // Swap the elements
}
}
swap(arr[i + 1], arr[high]); // Place pivot at the correct position
return (i + 1); // Return the index of the pivot
}
// Function to implement Quick Sort
void quickSort(int arr[], int low, int high) {
if (low < high) {
// pi is the partitioning index, arr[pi] is now in the correct position
int pi = partition(arr, low, high);
// Recursively sort the subarrays before and after partition
quickSort(arr, low, pi - 1); // Left subarray
quickSort(arr, pi + 1, high); // Right subarray
}
}
Let’s walk through an example to see how Quick Sort works.
Suppose we have the following unsorted array:
[38, 27, 43, 3, 9, 82, 10]
We pick the last element of the array as the pivot. In this case, the pivot is 10.
We rearrange the array such that elements smaller than 10 come to the left, and elements greater than 10 come to the right. After the partitioning, the array looks like this:
[3, 9, 10, 43, 38, 82, 27]
The pivot 10 is now in its correct sorted position (index 2).
Now, we recursively sort the left and right subarrays:
[3, 9] (indices 0 to 1)[43, 38, 82, 27] (indices 3 to 6)[3, 9]:9[3, 9], and 9 is in the correct position.Since this subarray has only two elements, it's already sorted.
[43, 38, 82, 27]:27[27, 38, 82, 43], and 27 is in the correct position.Now, we recursively sort the two subarrays:
[27] (already sorted).[38, 82, 43].[38, 82, 43]:43[38, 43, 82], and 43 is in the correct position.Now, we have two subarrays:
[38] (already sorted).[82] (already sorted).After all recursive calls are completed, the sorted array looks like this:
[3, 9, 10, 27, 38, 43, 82]
Quick Sort is known for its efficiency. The time complexity depends on how balanced the partitioning process is.
Best and Average Case:
Worst Case:
Worst-case time complexity can be reduced to O(n log n) by choosing a good pivot, such as using the median of three (the first, middle, and last element) as the pivot.
Space Complexity:
Space Complexity: O(log n) in the best case and O(n) in the worst case (for highly unbalanced partitions).
The choice of pivot has a significant effect on the performance of Quick Sort:
Quick Sort is one of the most efficient sorting algorithms, with an average time complexity of O(n log n). It is widely used because of its in-place sorting nature and excellent performance on large datasets. However, its performance can degrade to O(n²) if poor pivot selection leads to unbalanced partitions. By using strategies like random pivots or median of three, the chances of hitting the worst case can be minimized.
Open this section to load past papers