We have discussed the implementation of QuickSort using Lomuto partition scheme. Lomuto’s partition scheme is easy to implement as compared to Hoare scheme. This has inferior performance to Hoare’s QuickSort.
Lomuto’s Partition Scheme:
This algorithm works by assuming the pivot element as the last element. If any other element is given as a pivot element then swap it first with the last element. Now initialize two variables i as low and j also low, iterate over the array and increment i when arr[j] <= pivot and swap arr[i] with arr[j] otherwise increment only j. After coming out from the loop swap arr[i] with arr[hi]. This i stores the pivot element.
partition(arr[], lo, hi)
pivot = arr[hi]
i = lo-1 // place for swapping
for j := lo to hi – 1 do
if arr[j] <= pivot then
i = i + 1
swap arr[i] with arr[j]
swap arr[i+1] with arr[hi]
return i+1
Refer QuickSort for details of this partitioning scheme.
Below are implementations of this approach:-
C++
#include<bits/stdc++.h>
using namespace std;
int partition( int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for ( int j = low; j <= high- 1; j++)
{
if (arr[j] <= pivot)
{
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
void quickSort( int arr[], int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
void printArray( int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf ( "%d " , arr[i]);
printf ( "\n" );
}
int main()
{
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof (arr)/ sizeof (arr[0]);
quickSort(arr, 0, n-1);
printf ( "Sorted array: \n" );
printArray(arr, n);
return 0;
}
|
Java
import java.io.*;
class GFG
{
static void Swap( int [] array,
int position1,
int position2)
{
int temp = array[position1];
array[position1] = array[position2];
array[position2] = temp;
}
static int partition( int []arr, int low,
int high)
{
int pivot = arr[high];
int i = (low - 1 );
for ( int j = low; j <= high- 1 ; j++)
{
if (arr[j] <= pivot)
{
i++;
Swap(arr, i, j);
}
}
Swap(arr, i + 1 , high);
return (i + 1 );
}
static void quickSort( int []arr, int low,
int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1 );
quickSort(arr, pi + 1 , high);
}
}
static void printArray( int []arr, int size)
{
int i;
for (i = 0 ; i < size; i++)
System.out.print( " " + arr[i]);
System.out.println();
}
static public void main (String[] args)
{
int []arr = { 10 , 7 , 8 , 9 , 1 , 5 };
int n = arr.length;
quickSort(arr, 0 , n- 1 );
System.out.println( "Sorted array: " );
printArray(arr, n);
}
}
|
Python3
def partition(arr, low, high):
pivot = arr[high]
i = (low - 1 )
for j in range (low, high):
if (arr[j] < = pivot):
i + = 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1 ], arr[high] = arr[high], arr[i + 1 ]
return (i + 1 )
def quickSort(arr, low, high):
if (low < high):
pi = partition(arr, low, high)
quickSort(arr, low, pi - 1 )
quickSort(arr, pi + 1 , high)
def printArray(arr, size):
for i in range (size):
print (arr[i], end = " " )
print ()
arr = [ 10 , 7 , 8 , 9 , 1 , 5 ]
n = len (arr)
quickSort(arr, 0 , n - 1 )
print ( "Sorted array:" )
printArray(arr, n)
|
C#
using System;
class GFG
{
static void Swap( int [] array,
int position1,
int position2)
{
int temp = array[position1];
array[position1] = array[position2];
array[position2] = temp;
}
static int partition( int []arr, int low,
int high)
{
int pivot = arr[high];
int i = (low - 1);
for ( int j = low; j <= high- 1; j++)
{
if (arr[j] <= pivot)
{
i++;
Swap(arr, i, j);
}
}
Swap(arr, i + 1, high);
return (i + 1);
}
static void quickSort( int []arr, int low,
int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
static void printArray( int []arr, int size)
{
int i;
for (i = 0; i < size; i++)
Console.Write( " " + arr[i]);
Console.WriteLine();
}
static public void Main()
{
int []arr = {10, 7, 8, 9, 1, 5};
int n = arr.Length;
quickSort(arr, 0, n-1);
Console.WriteLine( "Sorted array: " );
printArray(arr, n);
}
}
|
Javascript
<script>
function Swap(array, position1, position2)
{
let temp = array[position1];
array[position1] = array[position2];
array[position2] = temp;
}
function partition(arr, low, high)
{
let pivot = arr[high];
let i = (low - 1);
for (let j = low; j <= high- 1; j++)
{
if (arr[j] <= pivot)
{
i++;
Swap(arr, i, j);
}
}
Swap(arr, i + 1, high);
return (i + 1);
}
function quickSort(arr, low, high)
{
if (low < high)
{
let pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
function printArray(arr, size)
{
let i;
for (i = 0; i < size; i++)
document.write( " " + arr[i]);
document.write( "<br/>" );
}
let arr = [10, 7, 8, 9, 1, 5];
let n = arr.length;
quickSort(arr, 0, n-1);
document.write( "Sorted array: " );
printArray(arr, n);
</script>
|
Output
Sorted array:
1 5 7 8 9 10
Time Complexity: O(N2)
Auxiliary Space: O(1)
Hoare’s Partition Scheme:
Hoare’s Partition Scheme works by initializing two indexes that start at two ends, the two indexes move toward each other until an inversion is (A smaller value on the left side and greater value on the right side) found. When an inversion is found, two values are swapped and the process is repeated.
Algorithm:
partition(arr[], lo, hi)
pivot = arr[lo]
i = lo - 1 // Initialize left index
j = hi + 1 // Initialize right index
// Find a value in left side greater
// than pivot
do
i = i + 1
while arr[i] < pivot
// Find a value in right side smaller
// than pivot
do
j--;
while (arr[j] > pivot);
if i >= j then
return j
swap arr[i] with arr[j]
Below are implementations of this approach:-
C++
#include <bits/stdc++.h>
using namespace std;
int partition( int arr[], int low, int high)
{
int pivot = arr[low];
int i = low - 1, j = high + 1;
while ( true ) {
do {
i++;
} while (arr[i] < pivot);
do {
j--;
} while (arr[j] > pivot);
if (i >= j)
return j;
swap(arr[i], arr[j]);
}
}
void quickSort( int arr[], int low, int high)
{
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi);
quickSort(arr, pi + 1, high);
}
}
void printArray( int arr[], int n)
{
for ( int i = 0; i < n; i++)
printf ( "%d " , arr[i]);
printf ( "\n" );
}
int main()
{
int arr[] = { 10, 7, 8, 9, 1, 5 };
int n = sizeof (arr) / sizeof (arr[0]);
quickSort(arr, 0, n - 1);
printf ( "Sorted array: \n" );
printArray(arr, n);
return 0;
}
|
Java
import java.io.*;
class GFG {
static int partition( int [] arr, int low, int high)
{
int pivot = arr[low];
int i = low - 1 , j = high + 1 ;
while ( true ) {
do {
i++;
} while (arr[i] < pivot);
do {
j--;
} while (arr[j] > pivot);
if (i >= j)
return j;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
static void quickSort( int [] arr, int low, int high)
{
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi);
quickSort(arr, pi + 1 , high);
}
}
static void printArray( int [] arr, int n)
{
for ( int i = 0 ; i < n; i++)
System.out.print( " " + arr[i]);
System.out.println();
}
static public void main(String[] args)
{
int [] arr = { 10 , 7 , 8 , 9 , 1 , 5 };
int n = arr.length;
quickSort(arr, 0 , n - 1 );
System.out.println( "Sorted array: " );
printArray(arr, n);
}
}
|
Python3
def partition(arr, low, high):
pivot = arr[low]
i = low - 1
j = high + 1
while ( True ):
i + = 1
while (arr[i] < pivot):
i + = 1
j - = 1
while (arr[j] > pivot):
j - = 1
if (i > = j):
return j
arr[i], arr[j] = arr[j], arr[i]
def quickSort(arr, low, high):
if (low < high):
pi = partition(arr, low, high)
quickSort(arr, low, pi)
quickSort(arr, pi + 1 , high)
def printArray(arr, n):
for i in range (n):
print (arr[i], end = " " )
print ()
arr = [ 10 , 7 , 8 , 9 , 1 , 5 ]
n = len (arr)
quickSort(arr, 0 , n - 1 )
print ( "Sorted array:" )
printArray(arr, n)
|
C#
using System;
class GFG {
static int partition( int [] arr, int low, int high)
{
int pivot = arr[low];
int i = low - 1, j = high + 1;
while ( true ) {
do {
i++;
} while (arr[i] < pivot);
do {
j--;
} while (arr[j] > pivot);
if (i >= j)
return j;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
static void quickSort( int [] arr, int low, int high)
{
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi);
quickSort(arr, pi + 1, high);
}
}
static void printArray( int [] arr, int n)
{
for ( int i = 0; i < n; i++)
Console.Write( " " + arr[i]);
Console.WriteLine();
}
static public void Main()
{
int [] arr = { 10, 7, 8, 9, 1, 5 };
int n = arr.Length;
quickSort(arr, 0, n - 1);
Console.WriteLine( "Sorted array: " );
printArray(arr, n);
}
}
|
Javascript
<script>
function partition(arr, low, high)
{
let pivot = arr[low];
let i = low - 1, j = high + 1;
while ( true ) {
do {
i++;
} while (arr[i] < pivot);
do {
j--;
} while (arr[j] > pivot);
if (i >= j)
return j;
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
function quickSort(arr, low, high)
{
if (low < high) {
let pi = partition(arr, low, high);
quickSort(arr, low, pi);
quickSort(arr, pi + 1, high);
}
}
function printArray(arr, n)
{
for (let i = 0; i < n; i++)
document.write( " " + arr[i]);
document.write( "</br>" );
}
let arr = [ 10, 7, 8, 9, 1, 5 ];
let n = arr.length;
quickSort(arr, 0, n - 1);
document.write( "Sorted array: " + "</br>" );
printArray(arr, n);
</script>
|
Output
Sorted array:
1 5 7 8 9 10
Time Complexity: O(N)
Auxiliary Space: O(1)
Note : If we change Hoare’s partition to pick the last element as pivot, then the Hoare’s partition may cause QuickSort to go into an infinite recursion. For example, {10, 5, 6, 20} and pivot is arr[high], then returned index will always be high and call to same QuickSort will be made. To handle a random pivot, we can always swap that random element with the first element and simply follow the above algorithm.
Comparison:
- Hoare’s scheme is more efficient than Lomuto’s partition scheme because it does three times fewer swaps on average, and it creates efficient partitions even when all values are equal.
- Like Lomuto’s partition scheme, Hoare partitioning also causes Quick sort to degrade to O(n^2) when the input array is already sorted, it also doesn’t produce a stable sort.
- Note that in this scheme, the pivot’s final location is not necessarily at the index that was returned, and the next two segments that the main algorithm recurs on are (lo..p) and (p+1..hi) as opposed to (lo..p-1) and (p+1..hi) as in Lomuto’s scheme.
- Both Hoare’s Partition, as well as Lomuto’s partition, are unstable.
Hoare partition algorithm |
Lomuto partition algorithm |
Generally, the first item or the element is assumed to be the initial pivot element. Some choose the middle element and even the last element. |
Generally, a random element of the array is located and picked and then exchanged with the first or the last element to give initial pivot values. In the aforementioned algorithm, the last element of the list is considered as the initial pivot element. |
It is a linear algorithm. |
It is also a linear algorithm. |
It is relatively faster. |
It is slower. |
It is slightly difficult to understand and to implement. |
It is easy to understand and easy to implement. |
It doesn’t fix the pivot element in the correct position. |
It fixes the pivot element in the correct position. |
Source : https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme
If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!