Dutch flag problem and quick sorting

Hello, I'm Monday.

In recent articles on algorithms, we talked about merge sorting. Merge sorting is almost the same. Today we talk about quick sorting.

1, Dutch flag issue

1. What is the Dutch flag

The Dutch flag is composed of red, white and blue stripes, as shown in the figure below:

Suppose that there are multiple stripes, the number of colors is different, and a new pattern is randomly formed. The new pattern may be as shown in the figure below, but it is not the only case:

The requirements are: arrange these stripes according to the color. The red one is in the upper part, the white one is in the middle part and the blue one is in the lower part. We call this kind of problem the Dutch flag problem.

2. Abstract of Dutch flag

We abstract the Dutch flag problem into an array as follows:

Given an integer array and a value m (existing in the original array), it is required to put the elements smaller than m in the array to the left of the array, the elements equal to m in the middle of the array, and the elements greater than m to the right of the array. Finally, an integer array is returned with only two values. The position of 0 is the left subscript value of the array part equal to M The 1 position is the lower right label value of the array part equal to M.

Further abstracted into a more general form is as follows:

Given the array arr, the number within the range of [l, r] (of course, the default is [0 - arr.length - 1]), less than arr[r] (here, the rightmost value of the array is directly taken for comparison) is placed on the left of the array, equal to arr[r] is placed in the middle of the array, and greater than arr[r] is placed on the right of the array. Finally, return the lower left and right label values equal to arr[r].

3. Solution ideas

Define a less than area and a greater than area; Traverse the array, compare with arr[r] one by one,

(1) Less than arr[r], exchange with the next position in the less than area, and move the current position backward;

(2) Equal to arr[r], the current position moves back directly;

(3) Greater than arr[r], exchange with the previous position greater than the area, and the current position does not move (the number exchanged to this position has not been compared, so it does not move).

After traversal, arr[r] and the leftmost position of the greater than area are exchanged.

Finally, return. At this time, it is less than the next position of the area and greater than the position of the area, that is, the last lower left and right label values equal to arr[r].

4. Detailed reference code

    /**
     * Dutch flag issue
     * <p>
     * Put the array arr, [l,   r] The number within the range, less than arr[r] to the left of the array, equal to arr[r] to the middle of the array, and greater than arr[r] to the right of the array
     *
     * @return Returns the left equal to arr[r],   Lower right label value
     */
    public static int[] netherlandsFlag(int[] arr, int l, int r) {
        if (l > r) {
            return new int[]{-1, -1};
        }
        if (l == r) {
            return new int[]{l, r};
        }
        //  The right boundary less than arr[r], starting from the left bit of L
        int less = l - 1;
        //  The left boundary greater than arr[r] starts from r, that is, there is already arr[r] in the current right boundary
        int more = r;
        //  Subscripts currently being compared
        int index = l;
        //  Not with   Left boundary greater than arr[r]   Hit
        while (index < more) {
            if (arr[index] < arr[r]) {
                //  When less than, the number of current positions is exchanged with the next position of the right boundary less than arr[r]
                //  Move the current position back one bit
                swap(arr, index++, ++less);
            } else if (arr[index] == arr[r]) {
                //  When equal to, the current position can be moved back one bit
                index++;
            } else {
                //  When greater than, the number of current positions is exchanged with the previous position of the left boundary greater than arr[r]
                //  The current position does not move
                swap(arr, index, --more);
            }
        }
        //  Swap the number of arr[r] positions with the number greater than the left bound of arr[r]
        //  At this point, the entire array is   Less than, equal to, greater than arr[r]   It is divided into three parts: left, middle and right
        swap(arr, more, r);

        //  Finally, in the whole array, the left and right boundaries equal to arr[r] are less respectively  +  1,   more
        return new int[]{less + 1, more};
    }

2, Quick sort

1. What is fast sorting (sorting process)

First, set a boundary value, and divide the array into three parts: left, middle and right.

(1) Gather the data less than the boundary value to the left of the array, the data equal to the boundary value to the middle of the array, and the data greater than the boundary value to the right of the array.

(2) Then, the data on the left and right can be sorted independently. For the data on the left, you can take another boundary value and divide this part of the data into three parts: left, middle and right. Similarly, put the smaller value on the left, the equal value in the middle and the larger value on the right. The data on the right is processed in the same way.

(3) By repeating the above process, it can be seen that this is a recursive process. After the left part is sorted recursively, the right part is sorted recursively. When the sorting of the data in the left and right parts is completed, the sorting of the whole array is completed.

After reading the process of fast platoon, do you find that the core method of fast platoon is the Dutch flag, so you know why this article introduces the Dutch flag at the beginning.

2. Abstract fast scheduling process

(1) Randomly place a number in the array at the comparison position (i.e. the rightmost position)

(2) Call the Dutch flag method (at this time, it is equal to the number of areas, that is, at the last ordered position), and get the left and right subscripts equal to the area

(3) The less than area and the greater than area can be sorted by recursively calling steps (1) and (2) respectively.

3. Detailed reference code

    /**
     * Random fast scheduling
     */
    public static void quickSortRandom(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        processRandom(arr, 0, arr.length - 1);
    }

    private static void processRandom(int[] arr, int l, int r) {
        if (l >= r) {
            return;
        }
        //  Randomly place a number in the array at the comparison position (i.e. the rightmost position of the array)
        //  This step is to ensure that the time complexity of fast scheduling is the key to O(N*logN). Otherwise, the time complexity of fast scheduling is O(N^2)
        swap(arr, l + (int) ((r - l + 1) * Math.random()), r);
        //  Divide the array into   Less than, equal to, greater than arr[r]   Left, middle and right
        int[] equalArea = netherlandsFlag(arr, l, r);
        //  At this time, the value equal to the area is already in the position of the last sorting result
        //  Recursively order the left half
        processRandom(arr, l, equalArea[0] - 1);
        //  Recursively order the right half
        processRandom(arr, equalArea[1] + 1, r);
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

Tags: Java Algorithm quick sort

Posted on Thu, 02 Dec 2021 19:47:29 -0500 by public-image