4

I was reading Skiena's Algorithm Design Manual, and couldn't solve this problem.

Suppose an array A consists of n elements, each of which is red, white, or blue. We seek to sort the elements so that all the reds come before all the whites, which come before all the blues The only operation permitted on the keys are

Examine(A,i) { report the color of the ith element of A.
Swap(A,i,j) { swap the ith element of A with the jth element.

Find a correct and efficient algorithm for red-white-blue sorting. There is a linear-time solution.

I tried using quicksort, and on 3 pivots, I should be able to solve it, but I don't know what to do when I see duplicates in quick sort.

9
  • So I how would I approach this? Now I officially have no approach. This is NOT HOW by the way, I am just trying to prepare for interviews. Commented Mar 3, 2013 at 15:04
  • 1
    Count of each colour in O(n); fix indexes; position the colours accordingly O(n). Commented Mar 3, 2013 at 15:05
  • 4
    Also google for the Dutch Flag algorithm. Commented Mar 3, 2013 at 15:06
  • @DoSparKot please read the question carefully. I can only use swap and examine. Commented Mar 3, 2013 at 15:08
  • 2
    why are you obsessed with using quicksort? It is not necessary! Commented Mar 3, 2013 at 15:35

6 Answers 6

2

Maintain two pointers: a red pointer pointing to 0 initially and a blue pointer pointing to the last element of array.

Now scan the array from left to right using the Examine function.

  • Every time you encounter a red element, swap it (using the Swap function) with the current red pointer and increment the red pointer.
  • Similarly, every time you encounter a blue element, swap it with the current blue pointer and decrement the blue pointer.
  • Increment the current pointer when you encounter a white element.
  • Stop when your current pointer crosses the blue pointer.

Now the array should be sorted as you want.

This is the Dutch National Flag Problem.

Sign up to request clarification or add additional context in comments.

9 Comments

"do not increment your current pointer if a (blue) swap was performed".
@WillNess it will work if you don't increment current pointer in case of a red swap too, just a little less efficient.
@AbhinavSarkar could give you me a small example. I don't see how this would work. Thanks!
(missed your whole sentence for some reason). Another problem is, it's not clear whether we are allowed at all to have these three additional variables to hold the indices.
@WillNess Yes you may 3 variables.
|
1

This is actually a very famous problem put forward by Dijkstra, known as the Dutch national flag problem.

The Wikipedia linked above gives a pretty decent account of how to approach this and other such problems.

A 3 way quick-sort may be applied to sole this as well. This presentation should give you a pretty good idea how to do so (the related content starts at page 37). Also, it does work in O(n) since the number of distinct keys is a constant, 3 (as stated on page 43).

4 Comments

Can I use quicksort for this?
@user2117772 one partition pass from quicksort will do it. But you need the variety with multiple pivots area, not just one pivot: in the end you'll have "smaller ones", then "bigger ones", then "those equal to pivot". No need for the final swap of the pivot into the middle, of course.
@user2117772: Yeah; O(n). I've edited my answer to reflect it. I hope it answers your question.
Following explains the three way quick sort approach along with complete code - algs4.cs.princeton.edu/23quicksort
0

This isn't really a sorting problem; it's a grouping problem.

Iterate through the list, counting the number of red, white, and blue elements. Now you know the exact structure of your solution, e.g.:

XXXXYYYYZZZZZZZZZ

Where X is red, Y is white, and Z is blue.

Now create three pointers: one at the location of the beginning of X, one at the beginning of Y, and one at the beginning of the Z in A.

Advance each pointer until it is at first element in its set that is wrong. For instance, if this is A:

XYXXYYXYZZZZZZZZZ

I

We would advance I, the X pointer, to the second position (index 1), because that element is out of place.

If you do that for each pointer, you know that each of the three pointers is pointing to an element out of place. Then iterate through the list. Whenever you find an element out of place, swap it with its corresponding pointer, i.e. if you find an X in the Ys, swap it with its Y pointer, and then increment that pointer (Y) until it is pointing to something out of place again.

Continue until the array is sorted.

Since you iterate through the list once (n ops) to get the structure and then each pointer at most will iterate through the list once (4 pointers → 4n), your total max runtime will be 5n which is O(n).

7 Comments

Can I use quicksort for this?
Quicksort is n log n run time, so that will break your n runtime constraint.
I feel like quicksort would be O(n) since I will be sweeping through the array once, with pivots changing such that less to the pivot is strictly less than, and to the right strictly greater than or equal to. I did it by hand using quick sort, but I can't quite fathom why it would be nlogn, and not n.
If you knew the pivots (which you do), quicksort should be the same as this algorithm. But that's only if you do it twice, and use the boundary locations between X, Y, and Z as pivots. In general, this would still take longer than O(n)
two O(n) passes is still O(n).
|
0

A very simple linear time algorithm is:

  1. Loop once through the array and find the counts of reds, whites and blues as rcount, wcount, bcount.

  2. Have three counters starting at 0, rcount, (rcount + wcount). Call them rcounter, wcounter and bcounter.

  3. For each counter, increment until you get to a color that is not the right one for that range

  4. Starting from 0, whenever you encounter a color: a. if the color is red and (counter < rcount), increment rcount and continue (likewise for white and blue depending on range) b. if the color is white, swap with wcounter and wcounter++ c. if the color is blue, swap with bcounter and bcounter++

When the loop ends you have your array.

7 Comments

I only have swap and examine as my methods
Ah, no increment operation ? There must be a goto next atleast, right ?
No. Strictly examine and swap
Well increment is implicit I would say. Examine i and then examine i+1 leads to increment. So is a loop compare. And it is likely provable that it can't be done without an increment or a loop.
Without a loop or increment you would be limited to constant time algorithms I expect.
|
0

I have gone through the Skiena book and saw this problem, too and here is my solution.

#include <stdio.h>

//swap the ith element of A with the jth element.
void swap(char arr[], int i, int j) {
    char temp;
    temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
    return;
}

int partition_color(char arr[], int low, int high, char color)
{
    int i;          // counter
    char p;          // pivot element
    int firsthing; // divider position for pivot

    p = color;          // choose the pivot element
    firsthing = high; // divider position for pivot element

    for (i = low; i < firsthing; i++) {
        if (arr[i] == color) {
            swap(arr, i, firsthing);
            firsthing--;
        }
    }

    return(firsthing);
}

void red_white_blue_sorting(char arr[], int n) {
    int pos;
    pos = partition_color(arr, 0, n, 'b');
    partition_color(arr, 0, pos, 'w');
    return;
}

int main() {

    char arr[] = {'r', 'b', 'r', 'w', 'b', 'w', 'b', 'r', 'r'};
    int n = sizeof(arr) / sizeof(arr[0]);

    red_white_blue_sorting(arr, n);
    for (int i = 0; i < n; i++)
        printf("%c ", arr[i]);

    printf("\n");
    return(0);
}

1 Comment

Can you give more info about the solution you provided?
-1

I was going through the Skiena book and saw this problem.

I got a solution with O(2n):

Suppose A = [B,R,W,R,W,B]

  1. First go through the array and partition pivoting B, so that, all the values that are R or W will be pushed to the front of the array.

Now A will be; ['R', 'W', 'R', 'W', 'B', 'B'] => O(n)

  1. Again go through A, pivoting on W, so that all the values that are R will be pushed to the front of the array. We can ignore B as they are already in place.

Result: ['R', 'R', 'W', 'W', 'B', 'B'] => O(2n)

This is a linear solution.

Is this correct way?

1 Comment

You shouldn't use write your question as an answer. Prefer writing a comment instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.