Quick Sort in C++

Challenge Inside! : Find out where you stand! Try quiz, solve problems & win rewards!

Learn via video course

C++ Course: Learn the Essentials
C++ Course: Learn the Essentials
By Prateek Narang
Free
star5
Enrolled: 1000
C++ Course: Learn the Essentials
C++ Course: Learn the Essentials
Prateek Narang
Free
5
icon_usercirclecheck-01Enrolled: 1000
Start Learning

Overview

Sorting is arranging an array's elements in increasing or decreasing order. We came across many sorting algorithms like count sort, merge sort, bubble sort, etc., with a certain time and space complexities.

Quick sort in C++ is a divide and conquer sorting algorithm to sort the array.

Scope

In this article, we will discuss below topics :

  • Quick sort algorithm in detail.
  • Complexity analysis of quick sort in C++(time and space both).
  • Real-world applications of quick sort.
  • Advantages and disadvantages of using a quick sort algorithm.

This article neither covers any detailed explanation of the 3-way quick sort and randomized quick sort algorithm nor does it covers code implementation in languages other than C++.

Introduction

As the name suggests, a quick sort algorithm is known to sort an array of elements much faster (twice or thrice times) than various sorting algorithms.

Quick sort uses the divide and conquer technique where we partition the array around an element known as the pivot element, which is chosen randomly from the array. We solve the partitions to achieve an ordered array. Due to this reason, it is also known as the Partition Exchange Algorithm.

Working Of Quick Sort Algorithm In C++

The quick sort algorithm works in a Divide and Conquer fashion :

  • Divide :-

Choose a pivot element first from the array. After that, divide the array into two subarrays, with each element in the left sub-array being less than or equal to the pivot element and each element in the right sub-array being greater. This will continue until only a single element is left in the sub-array.

  • Conquer :

Recursively, sort the two subarrays formed with a quick sort.

  • Merge :

Merge the already sorted array.

Working of Quick Sort Algorithm in C++

To discuss the working of the quick sort algorithm, let us take an example of an array:

  1. Select the pivot element:-

Firstly, we choose a pivot element from the element. There are many different ways of choosing a pivot element : * Pick the first element as pivot always. * Pick the last element as pivot always. * Pick a random element as a pivot. * Pick median element as pivot.

In this article, we will consider the last element of the array as the pivot element.

Select the Pivot element

  1. Rearrange the array:-

We will rearrange the array such that elements smaller than the pivot element will come before the pivot element, and elements larger than the pivot element will come after the pivot element. Hence pivot element will come to its actual position.

In the above example, elements [9,8][9,8] will come after [7][7], and [6,3,5,2][6,3,5,2] will come before [7][7].

Rearrange the array 1

We rearrange the array in the following way :

  • We initialize a pointer PIndex at index 0. This pointer will finally point to the pivot element's actual position.

Rearrange the array 2

  • Then we traverse the array till Pivot with a pointer. Let us say i and check for the following condition :

This way, we put all the smaller elements to the left of PIndex and all the larger elements to the right of the PIndex.

traverse the array till Pivot 1

traverse the array till Pivot 2

  • After array traversal and swapping, do PIndex= PIndex-1. This way, we rearranged the elements by partitioning the array into two subarrays- one to the left of the PIndex and one to the right of the PIndex.
  1. Divide subarrays: We pass the pivot index's left and right subarray recursively to the same process followed above. Therefore, in the above example, we pass subarray - [0 to 3] with pivot element as arr[3]arr[3] and subarray - [5 to 6] with pivot element as arr[6]arr[6] as the argument to the quickSort function again.

Divide subarrays

Sorted Array: final Sorted Array

Implementation Of Quicksort In C++

  • Firstly, we initiate two pointers, lo and hi, to the leftmost and rightmost elements of the array.
  • Then, we call the partition function, which rearranges the array such that all the smaller elements are left to the pivot element and all the larger elements are right to the pivot element.

It returns the final pivot index PIndex in the range [lo, hi].

  • Recursively call the quicksort for the left subarray of Pindex and the right subarray of the Pindex.

Pseudo Code :

C++ Code :

Output :

Quick Sort Complexity

  1. Time Complexity
CaseComplexity
Best CaseO(nlog(n))O(n*log(n))
Average CaseO(nlog(n))O(n*log(n))
Worst CaseO(nn)O(n*n)
  • Best-case complexity :

Arises when the pivot element is the middle element or close to the middle element in a quick sort. When the pivot index is found in the middle, the recursion branch spreads more evenly; hence, log(n)log(n) levels of the recursion tree are achieved.

Therefore, the best case time complexity is O(nlog(n))O(n*log(n)).

quick sort Best-case complexity

  • Average Case Complexity :

It occurs when the array elements are not sorted at all. In other words, the array is fully unordered.

In this case, the average case scenario is similar to the best-case scenario as the jumbled array also gives an evenly divided recursion stack. Hence, Quicksort's average case time complexity is O(nlog(n))O(n*log(n)).

  • Worst-Case Complexity :

In quick sort, worst-case complexity arises when the array is already sorted and the chosen pivot element is either the array's last or first element.

For example, if the array is [1,2,3,4,5][1,2,3,4,5] and the pivot is chosen as the leftmost element, we always get the pivot index as the first element. If the pivot index is the first element of the sorted array, recursion stack branches in the 1:n11: n-1 ratio give rise to nn levels of the recursion tree.

Hence, Quicksort's worst-case time complexity is O(nn)O(n*n).

quick sort Worst-Case Complexity

  1. Space Complexity
CaseComplexity
Best CaseO(log(n))O(log(n))
Average CaseO(log(n))O(log(n))
Worst CaseO(n)O(n)

As the algorithm is in place, where we sort the array in the original array, space complexity arises only because of the recursion stack. So, there must be a call stack entry for every one of these function calls.

This means that with an array of n integers, at worst, there will be n stack entries created, hence O(n)O(n) worst-case space complexity.

The average case space complexity arises when we create log(n)log(n) call stack entries. Hence average space complexity is O(logn)O(log n).

Characteristics Of Quick Sort

  • A stable sorting algorithm :

Maintains the position of two equal elements relative to one another. Quick sort is not a stable algorithm because elements are swapped according to the pivot’s position (without considering their original positions).

  • Quick sort algorithm is an in-place algorithm, which means array elements are sorted in the original array. In other words, the array is modified in the original array itself.
  • Quick sort is an algorithm for quickly and efficiently sorting an array or list. Because the algorithm is always in place, quick sort is used when the space is limited.

3-Way Quick sort (Dutch National flag)

In simple quick sort, we partition the array around the pivot element and recurse for the left and the right subarrays.

So, when array contains redundant elements with multiple occurrences like arr[]=[1,1,2,4,2,1,1,2,4,1,1,4,4,4]arr []=[1,1,2,4,2,1,1,2,4,1,1,4,4,4] with chosen pivot as 1 then we will be setting only one occurrence of 1 to its actual position in one recursive call.

To avoid this complexity, we use the 3-way Quick Sort algorithm, which partitions the array arr[l..r] into 3 subarrays :

  • arr[l...i] : Left subarray with elements less than the pivot element.
  • arr[i+1...j-1] : Subarray with elements equal to the pivot element.
  • arr[j...r] : Right subarray with elements greater than the pivot element.

Through this, we set the actual position of all the occurrences of 1 in a single pass. Thus 3-way quick sort can be used when we have more than one redundant element in the array.

Pseudo Code :

  • partition(arr, left, right, i, j) :
  • quicksort(arr, left, right) :

Randomized Quick Sort

Sometimes it happens when choosing the rightmost element in the sorted array as a pivot, resulting in a worst-case time complexity of O(nn)O(n*n).

In such cases, we use randomized quick sort algorithm, which is nothing but choosing a random pivot element from the array. Here we are probably choosing a pivot near the center of the array, and when this happens, the recursion branches spread more evenly, making it fast to sort the array elements in log(n)log(n) time.

Pseudocode(Lomuto partitioning) :

Note :

  • Using random pivoting, we improve the expected or average time complexity to O(nlog(n))O(n * log(n)). The Worst-Case complexity is still O(nn)O(n * n).
  • In internal sorting, all the data to sort is stored in memory at all times while sorting is in progress. In external sorting, data is stored outside memory (like on secondary memory) and only loaded into memory in small chunks.

Quick Sort vs. Merge Sort

FeaturesQuick sortMerge sort
PartitionsThe array is split into two parts around a pivot element and can be partitioned into any ratio.The array is partitioned into two halves(n/2)(n/2).
Worst case complexityO(nn)O(n*n)- We need to make many comparisons in the worst-case scenario.O(nlogn)O(n * log n) – same as the average case scenario.
Data sets usageIt is not efficient for larger data sets.It is efficient for all the data sets irrespective of size.
Additional spaceInplace – no need for additional space.Not in place – needs additional space to store auxiliary array.
Sorting methodInternal – data is sorted in the main memory.External – external memory is used for storing data arrays.
EfficiencyFaster and efficient for small size array.Fast and efficient for larger array and smaller both.
StabilityNot stable as two elements with the same values will not be placed relatively in the same order.Stable as two elements with the same values will appear in the same order in the sorted array.
Arrays/linked listsMore preferred for arrays.Works well for linked lists.

Quick Sort Applications

Quick sort provides a fast and systematic approach to sorting any list of things. Following are some of the applications where quick sort is used in real-world applications :

  • Commercial computing :

They are used in various government and private enterprises for sorting data such as accounts/profiles by name or any given ID, transactions by time or place, files by name or date of creation, and so on.

  • Numerical computations :

To accomplish accuracy in all calculations, most effectively created algorithms use priority queues and, in turn, sorting algorithms like quick sort.

  • Information search :

Sorting algorithms help improve information search, and quick sort in c++ is one of the fastest among all the sorting algorithms.

Advantages Of Quick sort

  • The time complexity of sorting an array of n elements in the average case scenario is O(nlog(n))O(n*log(n)) because an evenly divided recursion stack creates lognlogn levels for nn iterations. Hence, Quick sort is a bit faster(twice or thrice times) than merge sort.
  • Inplace algorithm : There is no need for additional storage.
  • Internal : Data is sorted in the main memory as a temporary array on RAM and not in the secondary memory.

Disadvantages Of Quick sort

  • Execution time varies depending on the elements of the array.
  • When the array is already sorted, the worst-case scenario for quick sort occurs(O(nn))(O(n*n)).
  • It is an unstable algorithm and hence, loses the relative ordering of the same elements in the array.

Conclusion

  • Quick sort in c++ uses the divide and conquer technique to sort elements of the array much faster than other sorting algorithms. It is also known as the Partition Exchange Algorithm.

  • We sort them by choosing a pivot, rearranging the array around it, and then calling recursively for both left and right subarrays around the pivot.

  • Quicksort's best-case time complexity is O(nlog(n))O(n*log(n)). In the worst-case scenario, it becomes O(nn)O(n*n) when all the elements are already sorted. The worst-case space complexity is O(n)O(n) for quicksort.

  • It is an in-place algorithm where sorting is done in the original array (cache-friendly).

  • We use the 3-way quick sort technique for redundant array elements.

  • We improve the worst-case scenario of a simple, quick sort by choosing a random pivot from the array(randomized quicksort).

  • Quick sort in C++ does not always partition the array into two halves, whereas, in merge sort, the partition is always into two halves.

  • In the real world, quicksort is generally used in commercial computing, numerical computations, and information search.

  • It is an unstable algorithm that does not preserve the relative ordering of the same elements from the original array.