3-Way QuickSort (Dutch National Flag)
Last Updated :
08 Mar, 2023
In simple QuickSort algorithm, we select an element as pivot, partition the array around a pivot and recur for subarrays on the left and right of the pivot.
Consider an array which has many redundant elements. For example, {1, 4, 2, 4, 2, 4, 1, 2, 4, 1, 2, 2, 2, 2, 4, 1, 4, 4, 4}. If 4 is picked as a pivot in Simple Quick Sort, we fix only one 4 and recursively process remaining occurrences.
The idea of 3 way Quick Sort is to process all occurrences of the pivot and is based on Dutch National Flag algorithm.
In 3 Way QuickSort, an array arr[l..r] is divided in 3 parts:
a) arr[l..i] elements less than pivot.
b) arr[i+1..j-1] elements equal to pivot.
c) arr[j..r] elements greater than pivot.
Below is the implementation of the above algorithm.
C++
#include <bits/stdc++.h>
using namespace std;
void partition( int a[], int l, int r, int & i, int & j)
{
i = l - 1, j = r;
int p = l - 1, q = r;
int v = a[r];
while ( true ) {
while (a[++i] < v)
;
while (v < a[--j])
if (j == l)
break ;
if (i >= j)
break ;
swap(a[i], a[j]);
if (a[i] == v) {
p++;
swap(a[p], a[i]);
}
if (a[j] == v) {
q--;
swap(a[j], a[q]);
}
}
swap(a[i], a[r]);
j = i - 1;
for ( int k = l; k < p; k++, j--)
swap(a[k], a[j]);
i = i + 1;
for ( int k = r - 1; k > q; k--, i++)
swap(a[i], a[k]);
}
void quicksort( int a[], int l, int r)
{
if (r <= l)
return ;
int i, j;
partition(a, l, r, i, j);
quicksort(a, l, j);
quicksort(a, i, r);
}
void printarr( int a[], int n)
{
for ( int i = 0; i < n; ++i)
printf ( "%d " , a[i]);
printf ( "\n" );
}
int main()
{
int a[] = { 4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4 };
int size = sizeof (a) / sizeof ( int );
printarr(a, size);
quicksort(a, 0, size - 1);
printarr(a, size);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static int i, j;
static void partition( int a[], int l, int r)
{
i = l - 1 ; j = r;
int p = l - 1 , q = r;
int v = a[r];
while ( true )
{
while (a[++i] < v)
;
while (v < a[--j])
if (j == l)
break ;
if (i >= j)
break ;
int temp = a[i];
a[i] = a[j];
a[j] = temp;
if (a[i] == v) {
p++;
temp = a[i];
a[i] = a[p];
a[p] = temp;
}
if (a[j] == v) {
q--;
temp = a[q];
a[q] = a[j];
a[j] = temp;
}
}
int temp = a[i];
a[i] = a[r];
a[r] = temp;
j = i - 1 ;
for ( int k = l; k < p; k++, j--)
{
temp = a[k];
a[k] = a[j];
a[j] = temp;
}
i = i + 1 ;
for ( int k = r - 1 ; k > q; k--, i++)
{
temp = a[i];
a[i] = a[k];
a[k] = temp;
}
}
static void quicksort( int a[], int l, int r)
{
if (r <= l)
return ;
i = 0 ; j = 0 ;
partition(a, l, r);
quicksort(a, l, j);
quicksort(a, i, r);
}
static void printarr( int a[], int n)
{
for ( int i = 0 ; i < n; ++i)
System.out.printf( "%d " , a[i]);
System.out.printf( "\n" );
}
public static void main(String[] args)
{
int a[] = { 4 , 9 , 4 , 4 , 1 , 9 , 4 , 4 , 9 , 4 , 4 , 1 , 4 };
int size = a.length;
printarr(a, size);
quicksort(a, 0 , size - 1 );
printarr(a, size);
}
}
|
Python3
def partition(arr, first, last, start, mid):
pivot = arr[last]
end = last
while (mid[ 0 ] < = end):
if (arr[mid[ 0 ]] < pivot):
arr[mid[ 0 ]], arr[start[ 0 ]] = arr[start[ 0 ]], arr[mid[ 0 ]]
mid[ 0 ] = mid[ 0 ] + 1
start[ 0 ] = start[ 0 ] + 1
elif (arr[mid[ 0 ]] > pivot):
arr[mid[ 0 ]], arr[end] = arr[end], arr[mid[ 0 ]]
end = end - 1
else :
mid[ 0 ] = mid[ 0 ] + 1
def quicksort(arr,first,last):
if (first > = last):
return
if (last = = first + 1 ):
if (arr[first] > arr[last]):
arr[first], arr[last] = arr[last], arr[first]
return
start = [first]
mid = [first]
partition(arr, first, last, start, mid)
quicksort(arr, first, start[ 0 ] - 1 )
quicksort(arr, mid[ 0 ], last)
arr = [ 4 , 9 , 4 , 4 , 1 , 9 , 4 , 4 , 9 , 4 , 4 , 1 , 4 ]
quicksort(arr, 0 , len (arr) - 1 )
print (arr)
|
C#
using System;
class GFG {
static void swap<T>( ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
public static void partition( int [] a, int l, int r,
ref int i, ref int j)
{
i = l - 1;
j = r;
int p = l - 1, q = r;
int v = a[r];
while ( true ) {
while (a[++i] < v)
;
while (v < a[--j])
if (j == l)
break ;
if (i >= j)
break ;
swap( ref a[i], ref a[j]);
if (a[i] == v) {
p++;
swap( ref a[p], ref a[i]);
}
if (a[j] == v) {
q--;
swap( ref a[j], ref a[q]);
}
}
swap( ref a[i], ref a[r]);
j = i - 1;
for ( int k = l; k < p; k++, j--)
swap( ref a[k], ref a[j]);
i = i + 1;
for ( int k = r - 1; k > q; k--, i++)
swap( ref a[i], ref a[k]);
}
public static void quicksort( int [] a, int l, int r)
{
if (r <= l)
return ;
int i = 0, j = 0;
partition(a, l, r, ref i, ref j);
quicksort(a, l, j);
quicksort(a, i, r);
}
public static void printarr( int [] a, int n)
{
for ( int i = 0; i < n; ++i)
Console.Write(a[i] + " " );
Console.Write( "\n" );
}
static void Main()
{
int [] a = { 4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4 };
int size = a.Length;
printarr(a, size);
quicksort(a, 0, size - 1);
printarr(a, size);
}
}
|
Javascript
<script>
var i, j;
function partition(a , l , r) {
i = l - 1;
j = r;
var p = l - 1, q = r;
var v = a[r];
while ( true ) {
while (a[++i] < v)
;
while (v < a[--j])
if (j == l)
break ;
if (i >= j)
break ;
var temp = a[i];
a[i] = a[j];
a[j] = temp;
if (a[i] == v) {
p++;
temp = a[i];
a[i] = a[p];
a[p] = temp;
}
if (a[j] == v) {
q--;
temp = a[q];
a[q] = a[j];
a[j] = temp;
}
}
var temp = a[i];
a[i] = a[r];
a[r] = temp;
j = i - 1;
for (k = l; k < p; k++, j--) {
temp = a[k];
a[k] = a[j];
a[j] = temp;
}
i = i + 1;
for (k = r - 1; k > q; k--, i++) {
temp = a[i];
a[i] = a[k];
a[k] = temp;
}
}
function quicksort(a , l , r) {
if (r <= l)
return ;
i = 0;
j = 0;
partition(a, l, r);
quicksort(a, l, j);
quicksort(a, i, r);
}
function printarr(a , n) {
for (i = 0; i < n; ++i)
document.write( " " + a[i]);
document.write( "<br/>" );
}
var a = [ 4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4 ];
var size = a.length;
printarr(a, size);
quicksort(a, 0, size - 1);
printarr(a, size);
</script>
|
Output
4 9 4 4 1 9 4 4 9 4 4 1 4
1 1 4 4 4 4 4 4 4 4 9 9 9
Time Complexity: O(N * log(N))
Where ‘N’ is the number of elements in the given array/list
The average number of recursive calls made to the quicksort function is log N, and every time the function is called we are traversing the given array/list which requires O(N) time. Thus, the total time complexity is O(N * log (N)).
Space Complexity: O(log N)
where ‘N’ is the number of elements in the given array/list.
Thanks to Utkarsh for suggesting above implementation.
Another Implementation using Dutch National Flag Algorithm
C++
#include <bits/stdc++.h>
using namespace std;
void swap( int * a, int * b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void printarr( int a[], int n)
{
for ( int i = 0; i < n; ++i)
printf ( "%d " , a[i]);
printf ( "\n" );
}
void partition( int a[], int low, int high, int & i, int & j)
{
if (high - low <= 1) {
if (a[high] < a[low])
swap(&a[high], &a[low]);
i = low;
j = high;
return ;
}
int mid = low;
int pivot = a[high];
while (mid <= high) {
if (a[mid] < pivot)
swap(&a[low++], &a[mid++]);
else if (a[mid] == pivot)
mid++;
else if (a[mid] > pivot)
swap(&a[mid], &a[high--]);
}
i = low - 1;
j = mid;
}
void quicksort( int a[], int low, int high)
{
if (low >= high)
return ;
int i, j;
partition(a, low, high, i, j);
quicksort(a, low, i);
quicksort(a, j, high);
}
int main()
{
int a[] = { 4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4 };
int size = sizeof (a) / sizeof ( int );
printarr(a, size);
quicksort(a, 0, size - 1);
printarr(a, size);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static void swap( int [] arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static void printarr( int a[], int n)
{
for ( int i = 0 ; i < n; ++i)
System.out.printf( "%d " , a[i]);
System.out.printf( "\n" );
}
static void partition( int a[], int low, int high, int i, int j)
{
if (high - low <= 1 ) {
if (a[high] < a[low])
swap(a, high, low);
i = low;
j = high;
return ;
}
int mid = low;
int pivot = a[high];
while (mid <= high) {
if (a[mid] < pivot)
swap(a, low++, mid++);
else if (a[mid] == pivot)
mid++;
else if (a[mid] > pivot)
swap(a, mid, high--);
}
i = low - 1 ;
j = mid;
}
static void quicksort( int a[], int low, int high)
{
if (low >= high)
return ;
int i=low, j=high;
partition(a, low, high, i, j);
quicksort(a, low, i);
quicksort(a, j, high);
}
public static void main(String[] args)
{
int a[] = { 4 , 9 , 4 , 4 , 1 , 9 , 4 , 4 , 9 , 4 , 4 , 1 , 4 };
int size = a.length;
printarr(a, size);
quicksort(a, 0 , size - 1 );
printarr(a, size);
}
}
|
Python3
def swap(a,i,j) :
temp = a[i]
a[i] = a[j]
a[j] = temp
def printarr(a, n) :
for i in range (n) :
print (a[i],end = ' ' )
print ( "\n" )
def partition(a, low, high, i, j) :
if high - low < = 1 :
if a[high] < a[low] :
swap(a,high, low)
i = low
j = high
return
mid = low; pivot = a[high];
while mid < = high :
if a[mid] < pivot :
swap(a,low,mid)
low + = 1
mid + = 1
elif a[mid] = = pivot :
mid + = 1
elif a[mid] > pivot :
swap(a,mid,high)
high - = 1
i = low - 1
j = mid
def quickSort(a,low,high) :
if low > = high :
return
i = low; j = high;
partition(a,low,high,i,j)
quickSort(a,low,i)
quickSort(a,j,high)
if __name__ = = "__main__" :
a = [ 4 , 9 , 4 , 4 , 1 , 9 , 4 , 4 , 9 , 4 , 4 , 1 , 4 ]
size = len (a)
printarr(a,size)
quickSort(a, 0 ,size - 1 )
printarr(a,size)
|
C#
using System;
class GFG {
static void swap<T>( ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
public static void printarr( int [] a, int n)
{
for ( int i = 0; i < n; ++i)
Console.Write(a[i] + " " );
Console.Write( "\n" );
}
public static void partition( int [] a, int low, int high,
ref int i, ref int j)
{
if (high - low <= 1) {
if (a[high] < a[low])
swap( ref a[high], ref a[low]);
i = low;
j = high;
return ;
}
int mid = low;
int pivot = a[high];
while (mid <= high) {
if (a[mid] < pivot)
swap( ref a[low++], ref a[mid++]);
else if (a[mid] == pivot)
mid++;
else if (a[mid] > pivot)
swap( ref a[mid], ref a[high--]);
}
i = low - 1;
j = mid;
}
public static void quicksort( int [] a, int low, int high)
{
if (low >= high)
return ;
int i = 0, j = 0;
partition(a, low, high, ref i, ref j);
quicksort(a, low, i);
quicksort(a, j, high);
}
static void Main()
{
int [] a = { 4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4 };
int size = a.Length;
printarr(a, size);
quicksort(a, 0, size - 1);
printarr(a, size);
}
}
|
Javascript
<script>
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function printarr(a, n) {
for (let i = 0; i < n; ++i)
document.write(a[i]);
document.write( "<br>" );
}
function partition(a, low, high, i, j) {
if (high - low <= 1) {
if (a[high] < a[low])
swap(a, high, low);
i = low;
j = high;
return ;
}
let mid = low;
let pivot = a[high];
while (mid <= high) {
if (a[mid] < pivot)
swap(a, low++, mid++);
else if (a[mid] == pivot)
mid++;
else if (a[mid] > pivot)
swap(a, mid, high--);
}
i = low - 1;
j = mid;
}
function quicksort(a, low, high) {
if (low >= high)
return ;
let i = low, j = high;
partition(a, low, high, i, j);
quicksort(a, low, i);
quicksort(a, j, high);
}
let a = [4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4];
let size = a.length;
printarr(a, size);
quicksort(a, 0, size - 1);
printarr(a, size);
</script>
|
Output
4 9 4 4 1 9 4 4 9 4 4 1 4
1 1 4 4 4 4 4 4 4 4 9 9 9
Time Complexity: O(N2) The time complexity for this code is O(N*log(N)) in the average and best-case scenarios, and O(N^2) in the worst-case scenario.
Space Complexity: O(log N)
Thanks Aditya Goel for this implementation.
Reference:
http://algs4.cs.princeton.edu/lectures/23DemoPartitioning.pdf
http://www.sorting-algorithms.com/quick-sort-3-way
Share your thoughts in the comments
Please Login to comment...