淺談排序算法之快速排序(6)

忙完論文的事,筆者終於有時間繼續學習算法了。以前一直覺得快速排序(Quick Sort)很神祕,今天筆者就學習一下《算法導論》關於快速排序的部分內容。
快速排序是一種最快情況時間複雜度爲O(n^2)的排序算法,但是其平均性能較好,且爲原址排序算法,因此像Java的Arrays類中的靜態函數sort就是使用快速排序實現的。與歸併排序算法一樣,快速排序也是使用了分治思想。對一個數組A[p…r]快速排序算法通常分爲三步:

  1. 數組A[p…r]被劃分爲兩個(可能爲空)的子數組A[p…q-1]和A[q+1…r],使得A[p…q-1]中的每一個元素都小於等於A[q],而A[q]也小於等於A[q+1…r]中的每一個元素。其中,計算小標q是快速排序算法中的一個重要步驟。
  2. 通過遞歸調用快速排序,對子數組A[p…q-1]和A[q+1…r]進行排序。
  3. 因爲子數組均爲原址排序,因此不需要進行合併操作。

演示代碼如下:

package org.vimist.pro.Algorithm.Sort;

import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Random;

/**
 * An illustration of {@code QuickSort}.
 *
 * @author Mr.K
 */
public class QuickSort {

    public static void main(String[] args) {
        int N = 20;
        Random random = new Random();
        int[] arr = new int[N];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt(3 * N);
        }
        System.out.println("待排序數組: " + Arrays.toString(arr));
        Quick_Sort(arr, 0, arr.length - 1);
        System.out.println("已排序數組: " + Arrays.toString(arr));
    }

    /**
     * Accepts an array, start index and end index and sorts the specified array
     * by using {@code QuickSort}, which is stable and this sort needs no spare
     * space.
     * <ul>
     *     <li>If index start is less than index end, the find the index i of primary
     *     element in the range [start, end], and invokes this method itself twice.
     *     In the first time, the 3-rd parameter changes to i - 1 and the 2-nd
     *     parameter changes to i + 1 in the second time when invoking itself.</li>
     * </ul>
     * Be careful, the complexity of time for this method may be O(n ^ 2) in the worst
     * cases, but in general, it comes to O(n * log(n)). In other word, this method
     * has good performance in general cases.
     *
     * @param arr   specified array to be sorted
     * @param start start index of the array
     * @param end   end index of the array
     */
    private static void Quick_Sort(@NotNull int[] arr, @NotNull int start, @NotNull int end) {
        if (start < end) {
            int mid = _partition(arr, start, end);
            Quick_Sort(arr, start, mid - 1);
            Quick_Sort(arr, mid + 1, end);
        }
    }

    /**
     * Core of {@code QuickSort}. This method is going to divide the specified
     * array into two sub-arrays, which may be empty. There exists a <em>For-
     * Loop</em>, which start from the index start(inclusive) and ends at the
     * index end(exclusive). In each iteration, if current element is less than
     * or equal to the last element in the specified array, then changes both
     * elements, one of which uses index <s>i</s>, which starts from start - 1.
     * After the end of <em>For-Loop</em>, exchanges both numbers, one of which
     * is represented by i + 1, and the other one is end. At last, return i + 1,
     * such that the elements in the range of [start, i] are less than or equal to
     * element indexed by i + 1, and the elements is in the range of [i + 2, end]
     * are greater than element indexed by i + 1.
     *
     * @param arr   specified array
     * @param start start index of array
     * @param end   end index of array
     * @return an index which separate specified array into two sub-arrays, where
     * all elements in the former array are less than or equals to the primary
     * element and all elements in the later array are greater than the primary
     * element.
     */
    private static int _partition(@NotNull int[] arr, @NotNull int start, @NotNull int end) {
        int x = arr[end], i = start - 1;
        for (int j = start; j < end; j++) {
            if (arr[j] <= x) {
                _exchange(arr, ++i, j);
            }
        }
        _exchange(arr, i + 1, end);
        return i + 1;
    }

    /**
     * Exchanges two numbers via specified indexes in the specified array.
     *
     * @param arr specified array
     * @param i   one of the specified index
     * @param j   another one of the specified index
     */
    private static void _exchange(@NotNull int[] arr, @NotNull int i, @NotNull int j) {
        int num = arr[i] ^ arr[j];
        arr[i] = num ^ arr[i];
        arr[j] = num ^ arr[j];
    }

}

運行結果如下:

待排序數組: [25, 9, 45, 9, 29, 15, 0, 7, 28, 10, 20, 31, 21, 6, 53, 30, 44, 26, 34, 33]
已排序數組: [0, 6, 7, 9, 9, 10, 15, 20, 21, 25, 26, 28, 29, 30, 31, 33, 34, 44, 45, 53]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章