3-Way QuickSort (Dutch National Flag)

In simple QuickSort algorithm, we select an element as pivot, partition the array around pivot and recur for subarrays on left and right of 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 pivot in Simple QuickSort, we fix only one 4 and recursively process remaining occurrences.

The idea of 3 way QuickSort is to process all occurrences of 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 above algorithm.

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program for 3-way quick sort
#include <bits/stdc++.h>
using namespace std;
  
/* This function partitions a[] in three parts
   a) a[l..i] contains all elements smaller than pivot
   b) a[i+1..j-1] contains all occurrences of pivot
   c) a[j..r] contains all elements greater than pivot */
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)
    {
        // From left, find the first element greater than
        // or equal to v. This loop will definitely terminate
        // as v is last element
        while (a[++i] < v);
  
        // From right, find the first element smaller than or
        // equal to v
        while (v < a[--j])
            if (j == l)
                break;
  
        // If i and j cross, then we are done
        if (i >= j) break;
  
        // Swap, so that smaller goes on left greater goes on right
        swap(a[i], a[j]);
  
        // Move all same left occurrence of pivot to beginning of
        // array and keep count using p
        if (a[i] == v)
        {
            p++;
            swap(a[p], a[i]);
        }
  
        // Move all same right occurrence of pivot to end of array
        // and keep count using q
        if (a[j] == v)
        {
            q--;
            swap(a[j], a[q]);
        }
    }
  
    // Move pivot element to its correct index
    swap(a[i], a[r]);
  
    // Move all left same occurrences from beginning
    // to adjacent to arr[i]
    j = i-1;
    for (int k = l; k < p; k++, j--)
        swap(a[k], a[j]);
  
    // Move all right same occurrences from end
    // to adjacent to arr[i]
    i = i+1;
    for (int k = r-1; k > q; k--, i++)
        swap(a[i], a[k]);
}
  
// 3-way partition based quick sort
void quicksort(int a[], int l, int r)
{
    if (r <= l) return;
  
    int i, j;
  
    // Note that i and j are passed as reference
    partition(a, l, r, i, j);
  
    // Recur
    quicksort(a, l, j);
    quicksort(a, i, r);
}
  
// A utility function to print an array
void printarr(int a[], int n)
{
    for (int i = 0; i < n; ++i)
        printf("%d  ", a[i]);
    printf("\n");
}
  
// Driver program
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;
}

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program for 3-way quick sort  
using System; 
    
class GFG 
    // A function which is used to swap values
    static void swap<T>(ref T lhs, ref T rhs)
    {
        T temp;
        temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
    /* This function partitions a[] in three parts 
       a) a[l..i] contains all elements smaller than pivot 
       b) a[i+1..j-1] contains all occurrences of pivot 
       c) a[j..r] contains all elements greater than pivot */
    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
        
            // From left, find the first element greater than 
            // or equal to v. This loop will definitely terminate 
            // as v is last element 
            while (a[++i] < v); 
        
            // From right, find the first element smaller than or 
            // equal to v 
            while (v < a[--j]) 
                if (j == l) 
                    break
        
            // If i and j cross, then we are done 
            if (i >= j) break
        
            // Swap, so that smaller goes on left greater goes on right 
            swap(ref a[i], ref a[j]); 
        
            // Move all same left occurrence of pivot to beginning of 
            // array and keep count using p 
            if (a[i] == v) 
            
                p++; 
                swap(ref a[p], ref a[i]); 
            
        
            // Move all same right occurrence of pivot to end of array 
            // and keep count using q 
            if (a[j] == v) 
            
                q--; 
                swap(ref a[j], ref a[q]); 
            
        
        
        // Move pivot element to its correct index 
        swap(ref a[i], ref a[r]); 
        
        // Move all left same occurrences from beginning 
        // to adjacent to arr[i] 
        j = i-1; 
        for (int k = l; k < p; k++, j--) 
            swap(ref a[k], ref a[j]); 
        
        // Move all right same occurrences from end 
        // to adjacent to arr[i] 
        i = i+1; 
        for (int k = r-1; k > q; k--, i++) 
            swap(ref a[i], ref a[k]); 
    
        
    // 3-way partition based quick sort 
    public static void quicksort(int[] a, int l, int r) 
    
        if (r <= l) return
        
        int i = 0, j = 0; 
        
        // Note that i and j are passed as reference 
        partition(a, l, r, ref i, ref j); 
        
        // Recur 
        quicksort(a, l, j); 
        quicksort(a, i, r); 
    
        
    // A utility function to print an array 
    public static void printarr(int[] a, int n) 
    
        for (int i = 0; i < n; ++i) 
            Console.Write(a[i] + " "); 
        Console.Write("\n"); 
    
        
    // Driver program 
    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); 
    }
    //This code is contributed by DrRoot_
}

chevron_right


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

Thanks to Utkarsh for suggesting above implementation.

Another Implementation using Dutch National Flag Algorithm

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program for 3-way quick sort
#include <bits/stdc++.h>
using namespace std;
  
void swap(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
  
// A utility function to print an array
void printarr(int a[], int n)
{
    for (int i = 0; i < n; ++i)
        printf("%d ", a[i]);
    printf("\n");
}
  
/* This function partitions a[] in three parts
a) a[l..i] contains all elements smaller than pivot
b) a[i+1..j-1] contains all occurrences of pivot
c) a[j..r] contains all elements greater than pivot */
  
//It uses Dutch National Flag Algorithm
void partition(int a[], int low, int high, int &i, int &j)
{
    // To handle 2 elements
    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--]);
    }
  
    //update i and j
    i = low-1;
    j = mid; //or high-1
}
  
// 3-way partition based quick sort
void quicksort(int a[], int low, int high)
{
    if (low>=high) //1 or 0 elements
        return;
  
    int i, j;
  
    // Note that i and j are passed as reference
    partition(a, low, high, i, j);
  
    // Recur two halves
    quicksort(a, low, i);
    quicksort(a, j, high);
}
  
// Driver program
int main()
{
    int a[] = {4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4};
    //int a[] = {4, 39, 54, 14, 31, 89, 44, 34, 59, 64, 64, 11, 41};
    //int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    //int a[] = {91, 82, 73, 64, 55, 46, 37, 28, 19, 10};
    //int a[] = {4, 9, 4, 4, 9, 1, 1, 1};
    int size = sizeof(a) / sizeof(int);
  
    printarr(a, size);
    quicksort(a, 0, size - 1);
    printarr(a, size);
    return 0;
}

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program for 3-way quick sort 
using System; 
    
class GFG 
    // A function which is used to swap values
    static void swap<T>(ref T lhs, ref T rhs)
    {
        T temp;
        temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
        
    // A utility function to print an array 
    public static void printarr(int[] a, int n) 
    
        for (int i = 0; i < n; ++i) 
            Console.Write(a[i] + " "); 
        Console.Write("\n"); 
    
        
    /* This function partitions a[] in three parts 
    a) a[l..i] contains all elements smaller than pivot 
    b) a[i+1..j-1] contains all occurrences of pivot 
    c) a[j..r] contains all elements greater than pivot */
        
    //It uses Dutch National Flag Algorithm 
    public static void partition(int[] a, int low, int high, ref int i, ref int j) 
    
        // To handle 2 elements 
        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--]); 
        
        
        //update i and j 
        i = low-1; 
        j = mid; //or high-1 
    
        
    // 3-way partition based quick sort 
    public static void quicksort(int[] a, int low, int high) 
    
        if (low>=high) //1 or 0 elements 
            return
        
        int i = 0 , j = 0; 
        
        // Note that i and j are passed as reference 
        partition(a, low, high, ref i, ref j); 
        
        // Recur two halves 
        quicksort(a, low, i); 
        quicksort(a, j, high); 
    
        
    // Driver program
    static void Main() 
    
        int[] a = {4, 9, 4, 4, 1, 9, 4, 4, 9, 4, 4, 1, 4}; 
        //int[] a = {4, 39, 54, 14, 31, 89, 44, 34, 59, 64, 64, 11, 41}; 
        //int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
        //int[] a = {91, 82, 73, 64, 55, 46, 37, 28, 19, 10}; 
        //int[] a = {4, 9, 4, 4, 9, 1, 1, 1}; 
        int size = a.Length; 
        
        printarr(a, size); 
        quicksort(a, 0, size - 1); 
        printarr(a, size); 
    }
    //This code is contributed by DrRoot_
}

chevron_right


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

Thanks Aditya Goel for this implementation.

Reference:
http://algs4.cs.princeton.edu/lectures/23DemoPartitioning.pdf
http://www.sorting-algorithms.com/quick-sort-3-way

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up

Improved By : DrRoot_, arnavvarshney



Article Tags :
Practice Tags :


10


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.