Given an array A[] consisting 0s, 1s and 2s, write a function that sorts A[]. The functions should put all 0s first, then all 1s and all 2s in last.
This is an variation of famous Dutch national flag problem.
The problem was posed with three colours, here `0′, `1′ and `2′. The array is divided into four sections:
- a[1..Lo-1] zeroes (red)
- a[Lo..Mid-] ones (white)
- a[Mid..Hi] unknown
- a[Hi+1..N] twos (blue)
The unknown region is shrunk while maintaining these conditions
- Lo := 1; Mid := 1; Hi := N;
- while Mid <= Hi do
- Invariant: a[1..Lo-1]=0 and a[Lo..Mid-1]=1 and a[Hi+1..N]=2; a[Mid..Hi] are unknown.
- case a[Mid] in
- 0: swap a[Lo] and a[Mid]; Lo++; Mid++
- 1: Mid++
- 2: swap a[Mid] and a[Hi]; Hi–
void
sort012(
int
a[],
int
arr_size)
{
int
lo = 0;
int
hi = arr_size - 1;
int
mid = 0;
while
(mid <= hi)
{
switch
(a[mid])
{
case
0:
swap(&a[lo++], &a[mid++]);
break
;
case
1:
mid++;
break
;
case
2:
swap(&a[mid], &a[hi--]);
break
;
}
}
}
Given an array and a range [lowVal, highVal], partition the array around the range such that array is divided in three parts.
1) All elements smaller than lowVal come first.
2) All elements in range lowVal to highVVal come next.
3) All elements greater than highVVal appear in the end.
The individual elements of three sets can appear in any order.
1) All elements smaller than lowVal come first.
2) All elements in range lowVal to highVVal come next.
3) All elements greater than highVVal appear in the end.
The individual elements of three sets can appear in any order.
A simple solution is to sort the array. This solution does a lot of extra rearrangements and requires O(n Log n) time.
An efficient solution is based on Dutch National Flag based QuickSort. We traverse given array elements from left. We keep track of two pointers, first (called start in below code) to store next position of smaller element (smaller than range) from beginning; and second (called end in below code) to store next position of greater element from end.
// Partitions arr[0..n-1] around [lowVal..highVal]
public
static
void
threeWayPartition(
int
[] arr,
int
lowVal,
int
highVal)
{
int
n = arr.length;
// Initialize ext available positions for
// smaller (than range) and greater lements
int
start =
0
, end = n-
1
;
// Traverse elements from left
for
(
int
i =
0
; i < end;)
{
// If current element is smaller than
// range, put it on next available smaller
// position.
if
(arr[i] < lowVal)
{
int
temp = arr[start];
arr[start] = arr[i];
arr[i] = temp;
start++;
i++;
}
// If current element is greater than
// range, put it on next available greater
// position.
else
if
(arr[i] > highVal)
{
int
temp = arr[end];
arr[end] = arr[i];
arr[i] = temp;
end--;
}
else
i++;
}
}
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.
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.
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);
}
Another Implementation using 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);
}