Related Articles

# QuickSort Tail Call Optimization (Reducing worst case space to Log n )

Prerequisite : Tail Call Elimination

In QuickSort, partition function is in-place, but we need extra space for recursive function calls. A simple implementation of QuickSort makes two calls to itself and in worst case requires O(n) space on function call stack.

The worst case happens when the selected pivot always divides the array such that one part has 0 elements and other part has n-1 elements. For example, in below code, if we choose last element as pivot, we get worst case for sorted arrays (See this for visualization)

## C++

 `#include `   `// Function to partition the array and return the pivot index` `int` `partition(``int` `arr[], ``int` `low, ``int` `high) {` `    ``int` `pivot = arr[high]; ``// Choose the pivot as the last element` `    ``int` `i = low - 1; ``// Initialize the index of the smaller element`   `    ``for` `(``int` `j = low; j < high; j++) {` `        ``// If the current element is smaller than or equal to the pivot` `        ``if` `(arr[j] <= pivot) {` `            ``i++; ``// Increment the index of the smaller element` `            ``std::swap(arr[i], arr[j]); ``// Swap arr[i] and arr[j]` `        ``}` `    ``}`   `    ``// Swap the pivot element with the element at index (i + 1)` `    ``std::swap(arr[i + 1], arr[high]);`   `    ``return` `i + 1; ``// Return the pivot index` `}`   `// Function to perform the QuickSort algorithm` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high) {` `    ``if` `(low < high) {` `        ``// Find the pivot index such that elements smaller than the pivot` `        ``// are on the left and elements greater than the pivot are on the right` `        ``int` `pi = partition(arr, low, high);`   `        ``// Recursively sort the elements before and after the pivot` `        ``quickSort(arr, low, pi - 1);` `        ``quickSort(arr, pi + 1, high);` `    ``}` `}`   `int` `main() {` `    ``int` `arr[] = {12, 11, 13, 5, 6, 7};` `    ``int` `n = ``sizeof``(arr) / ``sizeof``(arr);`   `    ``std::cout << ``"Original array: "``;` `    ``for` `(``int` `i = 0; i < n; i++) {` `        ``std::cout << arr[i] << ``" "``;` `    ``}` `    ``std::cout << std::endl;`   `    ``quickSort(arr, 0, n - 1);`   `    ``std::cout << ``"Sorted array: "``;` `    ``for` `(``int` `i = 0; i < n; i++) {` `        ``std::cout << arr[i] << ``" "``;` `    ``}` `    ``std::cout << std::endl;`   `    ``return` `0;` `}`

## C

 `/* A Simple implementation of QuickSort that makes two` `   ``two recursive calls. */` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``if` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);` ` `  `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - 1);` `        ``quickSort(arr, pi + 1, high);` `    ``}` `}` `// See below link for complete running code` `// https://www.geeksforgeeks.org/quick-sort/`

## Java

 `// A Simple implementation of QuickSort that ` `// makes two recursive calls. ` `static` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``if` `(low < high)` `    ``{` `        `  `        ``// pi is partitioning index, arr[p] is ` `        ``// now at right place ` `        ``int` `pi = partition(arr, low, high);` `        `  `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - ``1``);` `        ``quickSort(arr, pi + ``1``, high);` `    ``}` `}`   `// This code is contributed by rutvik_56`

## Python3

 `# Python3 program for the above approach` `def` `quickSort(arr, low, high):` `    `  `    ``if` `(low < high):` `    `  `        ``# pi is partitioning index, arr[p] is now` `        ``# at right place` `        ``pi ``=` `partition(arr, low, high)` `  `  `        ``# Separately sort elements before` `        ``# partition and after partition` `        ``quickSort(arr, low, pi ``-` `1``)` `        ``quickSort(arr, pi ``+` `1``, high)`   `# This code is contributed by sanjoy_62`

## C#

 `// A Simple implementation of QuickSort that ` `// makes two recursive calls. ` `static` `void` `quickSort(``int` `[]arr, ``int` `low, ``int` `high)` `{` `    ``if` `(low < high)` `    ``{` `        `  `        ``// pi is partitioning index, arr[p] is ` `        ``// now at right place ` `        ``int` `pi = partition(arr, low, high);` `        `  `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - 1);` `        ``quickSort(arr, pi + 1, high);` `    ``}` `}`   `// This code is contributed by pratham76.`

## Javascript

 ``

Can we reduce the auxiliary space for function call stack?
We can limit the auxiliary space to O(Log n). The idea is based on tail call elimination. As seen in the previous post, we can convert the code so that it makes one recursive call. For example, in the below code, we have converted the above code to use a while loop and have reduced the number of recursive calls.

## C++

 `/* QuickSort after tail call elimination */` `#include `   `using` `namespace` `std;`   `// A utility function to swap two elements` `void` `swap(``int``* a, ``int``* b)` `{` `    ``int` `t = *a;` `    ``*a = *b;` `    ``*b = t;` `}`   `/* This function takes last element as pivot, places` `   ``the pivot element at its correct position in sorted` `    ``array, and places all smaller (smaller than pivot)` `   ``to left of pivot and all greater elements to right` `   ``of pivot */` `int` `partition(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``int` `pivot = arr[high]; ``// pivot` `    ``int` `i = (low - 1); ``// Index of smaller element`   `    ``for` `(``int` `j = low; j <= high- 1; j++)` `    ``{` `        ``// If current element is smaller than or` `        ``// equal to pivot` `        ``if` `(arr[j] <= pivot)` `        ``{` `            ``i++; ``// increment index of smaller element` `            ``swap(&arr[i], &arr[j]);` `        ``}` `    ``}` `    ``swap(&arr[i + 1], &arr[high]);` `    ``return` `(i + 1);` `}`   `/* The main function that implements QuickSort` ` ``arr[] --> Array to be sorted,` `  ``low  --> Starting index,` `  ``high  --> Ending index */` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``if` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);` `        `  `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - 1);` `        ``quickSort(arr, pi + 1, high);` `    ``}` `}` `/* Function to print an array */` `void` `printArray(``int` `arr[], ``int` `size)` `{` `    ``for` `(``int` `i = 0; i < size; i++)` `        ``cout << arr[i] << ``" "``;` `    ``cout << endl;` `}` `// Driver program to test above functions` `int` `main()` `{` `    ``int` `arr[] = {10, 7, 8, 9, 1, 5};` `    ``int` `n = ``sizeof``(arr)/``sizeof``(arr);` `    ``quickSort(arr, 0, n - 1);` `    ``cout << ``"Sorted array: \n"``;` `    ``printArray(arr, n);` `    ``return` `0;` `}` `// This code code is contributed by shivhack999`

## C

 `/* QuickSort after tail call elimination using while loop */` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``while` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);`   `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - 1);`   `        ``low = pi+1;` `    ``}` `}` `// See below link for complete running code` `// https://ide.geeksforgeeks.org/qrlM31`

## Java

 `/* QuickSort after tail call elimination using while loop */` `static` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``while` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);`   `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - ``1``);`   `        ``low = pi+``1``;` `    ``}` `}` `// See below link for complete running code` `// https://ide.geeksforgeeks.org/qrlM31`   `// This code is contributed by gauravrajput1`

## Python3

 `# QuickSort after tail call elimination using while loop '''` `def` `quickSort(arr, low, high):` `    ``while` `(low < high):`   `        ``# pi is partitioning index, arr[p] is now` `        ``#  at right place '''` `        ``pi ``=` `partition(arr, low, high)`   `        ``# Separately sort elements before` `        ``# partition and after partition` `        ``quickSort(arr, low, pi ``-` `1``)`   `        ``low ``=` `pi``+``1`   `# See below link for complete running code` `# https:#ide.geeksforgeeks.org/qrlM31`   `# This code is contributed by gauravrajput1`

## C#

 `/* QuickSort after tail call elimination using while loop */` `static` `void` `quickSort(``int` `[]arr, ``int` `low, ``int` `high)` `{` `    ``while` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);`   `        ``// Separately sort elements before` `        ``// partition and after partition` `        ``quickSort(arr, low, pi - 1);`   `        ``low = pi+1;` `    ``}` `}` `// See below link for complete running code` `// https://ide.geeksforgeeks.org/qrlM31`     `// This code contributed by gauravrajput1`

## Javascript

 ``

Although we have reduced number of recursive calls, the above code can still use O(n) auxiliary space in worst case. In worst case, it is possible that array is divided in a way that the first part always has n-1 elements. For example, this may happen when last element is choses as pivot and array is sorted in increasing order.

We can optimize the above code to make a recursive call only for the smaller part after partition. Below is implementation of this idea.

Further Optimization :

## C++

 `// C++ program of the above approach` `#include ` `using` `namespace` `std;`   `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `  ``while` `(low < high)` `  ``{` `    ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `    ``int` `pi = partition(arr, low, high);`   `    ``// If left part is smaller, then recur for left` `    ``// part and handle right part iteratively` `    ``if` `(pi - low < high - pi)` `    ``{` `      ``quickSort(arr, low, pi - 1);` `      ``low = pi + 1;` `    ``}`   `    ``// Else recur for right part` `    ``else` `    ``{` `      ``quickSort(arr, pi + 1, high);` `      ``high = pi - 1;` `    ``}` `  ``}` `}`   `// This code is contributed by code_hunt.`

## C

 `/* This QuickSort requires O(Log n) auxiliary space in` `   ``worst case. */` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``while` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);`   `        ``// If left part is smaller, then recur for left` `        ``// part and handle right part iteratively` `        ``if` `(pi - low < high - pi)` `        ``{` `            ``quickSort(arr, low, pi - 1);` `            ``low = pi + 1;` `        ``}`   `        ``// Else recur for right part` `        ``else` `        ``{` `            ``quickSort(arr, pi + 1, high);` `            ``high = pi - 1;` `        ``}` `    ``}` `}` `// See below link for complete running code` `// https://ide.geeksforgeeks.org/LHxwPk`

## Java

 `/* This QuickSort requires O(Log n) auxiliary space in` `   ``worst case. */` `static` `void` `quickSort(``int` `arr[], ``int` `low, ``int` `high)` `{` `    ``while` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);`   `        ``// If left part is smaller, then recur for left` `        ``// part and handle right part iteratively` `        ``if` `(pi - low < high - pi)` `        ``{` `            ``quickSort(arr, low, pi - ``1``);` `            ``low = pi + ``1``;` `        ``}`   `        ``// Else recur for right part` `        ``else` `        ``{` `            ``quickSort(arr, pi + ``1``, high);` `            ``high = pi - ``1``;` `        ``}` `    ``}` `}` `// See below link for complete running code` `// https://ide.geeksforgeeks.org/LHxwPk`   `// This code is contributed by gauravrajput1 `

## Python3

 `''' This QuickSort requires O(Log n) auxiliary space in` `   ``worst case. '''` `def` `quickSort(arr, low, high)` `{` `    ``while` `(low < high):` `        ``''' pi is partitioning index, arr[p] is now` `           ``at right place '''` `        ``pi ``=` `partition(arr, low, high);`   `        ``# If left part is smaller, then recur for left` `        ``# part and handle right part iteratively` `        ``if` `(pi ``-` `low < high ``-` `pi):` `            ``quickSort(arr, low, pi ``-` `1``);` `            ``low ``=` `pi ``+` `1``;` `        `  `        ``# Else recur for right part` `        ``else``:` `            ``quickSort(arr, pi ``+` `1``, high);` `            ``high ``=` `pi ``-` `1``;`   `# See below link for complete running code` `# https:#ide.geeksforgeeks.org/LHxwPk`   `# This code is contributed by gauravrajput1`

## C#

 `/* This QuickSort requires O(Log n) auxiliary space in` `   ``worst case. */` `static` `void` `quickSort(``int` `[]arr, ``int` `low, ``int` `high)` `{` `    ``while` `(low < high)` `    ``{` `        ``/* pi is partitioning index, arr[p] is now` `           ``at right place */` `        ``int` `pi = partition(arr, low, high);`   `        ``// If left part is smaller, then recur for left` `        ``// part and handle right part iteratively` `        ``if` `(pi - low < high - pi)` `        ``{` `            ``quickSort(arr, low, pi - 1);` `            ``low = pi + 1;` `        ``}`   `        ``// Else recur for right part` `        ``else` `        ``{` `            ``quickSort(arr, pi + 1, high);` `            ``high = pi - 1;` `        ``}` `    ``}` `}` `// See below link for complete running code` `// https://ide.geeksforgeeks.org/LHxwPk`     `// This code is contributed by gauravrajput1`

## Javascript

 ``

In the above code, if left part becomes smaller, then we make recursive call for left part. Else for the right part. In worst case (for space), when both parts are of equal sizes in all recursive calls, we use O(Log n) extra space.