天天看點

雙路快速排序

雙路快速排序算法是随機化快速排序的改進版本,partition 過程使用兩個索引值(i、j)用來周遊數組,将 <v 的元素放在索引i所指向位置的左邊,而将 >v 的元素放在索引j所指向位置的右邊,v 代表标定值。

時間和空間複雜度同随機化快速排序。 對于有大量重複元素的數組,如果使用上一節随機化快速排序效率是非常低的,導緻 partition 後大于基點或者小于基點資料的子數組長度會極度不平衡,甚至會退化成 O(n*2) 時間複雜度的算法,對這種情況可以使用雙路快速排序算法。

使用兩個索引值(i、j)用來周遊我們的序列,将 <=v 的元素放在索引 i 所指向位置的左邊,而将 >=v 的元素放在索引 j 所指向位置的右邊,平衡左右兩邊子數組。

雙路快速排序

源碼包下載下傳:Download

package runoob;

/**

 * 雙路快速排序

 */

public class QuickSort2Ways {

    //核心代碼---開始

    private static int partition(Comparable[] arr, int l, int r){

        // 随機在arr[l...r]的範圍中, 選擇一個數值作為标定點pivot

        swap( arr, l , (int)(Math.random()*(r-l+1))+l );

        Comparable v = arr[l];

        // arr[l+1...i) <= v; arr(j...r] >= v

        int i = l+1, j = r;

        while( true ){

            while( i <= r && arr[i].compareTo(v) < 0 )

                i ++;

            while( j >= l+1 && arr[j].compareTo(v) > 0 )

                j --;

            if( i > j )

                break;

            swap( arr, i, j );

            i ++;

            j --;

        }

        swap(arr, l, j);

        return j;

    }

    //核心代碼---結束

    // 遞歸使用快速排序,對arr[l...r]的範圍進行排序

    private static void sort(Comparable[] arr, int l, int r){

        if (l >= r) {

            return;

        int p = partition(arr, l, r);

        sort(arr, l, p-1 );

        sort(arr, p+1, r);

    public static void sort(Comparable[] arr){

        int n = arr.length;

        sort(arr, 0, n-1);

    private static void swap(Object[] arr, int i, int j) {

        Object t = arr[i];

        arr[i] = arr[j];

        arr[j] = t;

    // 測試 QuickSort

    public static void main(String[] args) {

        // 雙路快速排序算法也是一個O(nlogn)複雜度的算法

        // 可以在1秒之内輕松處理100萬數量級的資料

        // Quick Sort也是一個O(nlogn)複雜度的算法

        int N = 1000000;

        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 100000);

        sort(arr);

        SortTestHelper.printArray(arr);

}