快速排序 java實現 (原理-優化) 三路快排


一、基本的快速排序

在數組中選取一個元素為基點,然后想辦法把這個基點元素移動到它在排好序后的最終位置,使得新數組中在這個基點之前的元素都小於這個基點,而之后的元素都大於這個基點,然后再對前后兩部分數組快速排序,直到數組排序完成。

 代碼實現:

    public void quickSorted ( int arr[] ) {

        int n = arr.length - 1;            // 閉區間 [0...n]
        __quickSorted (arr, 0, n);
    }

    private __quickSorted( int arr[], int L, int R) {

        if ( (L >= R) {
            return;
        }

        // 將基點移動到最終位置的方法
        int p = __partioner(arr, L, R);

        // 遞歸拆分數組
        __quickSorted(arr, L, p - 1);
        __quickSorted(arr, p + 1, R);
    }

 

那么最大的問題就是怎么把這個基點移動到它最終應該所在的位置。

代碼實現:

    private int __partioner ( int arr[], int L, int R ) {

        int v = arr[L];

        // [L + 1, j] < v ; [j + 1, i) > v;
        int j = L;

        for ( int i = L + 1; i <= R; i++ ) {
            if ( arr[i] < v) {
                // 交換 arr[i] 和 arr [j + 1]
                int tmp = arr[j + 1];
                arr[j + 1] = arr[i];
                arr[i] = tmp;
                j++;
            }
        }
        // 交換 arr[j]  和arr[L]
        int tmp = arr[j];
        arr[j] = arr[L];
        arr[L] = tmp;

        return j;
    }

 

最終實現:

    public void quickSorted ( int arr[] ) {

        int n = arr.length - 1;            // 閉區間 [0...n]
        __quickSorted (arr, 0, n);
    }

    private __quickSorted( int arr[], int L, int R) {

        if ( (L >= R) {
            return;
        }

        // 將基點移動到最終位置的方法
        int p = __partioner(arr, L, R);

        // 遞歸拆分數組
        __quickSorted(arr, L, p - 1);
        __quickSorted(arr, p + 1, R);
    }

    private int __partioner ( int arr[], int L, int R ) {

        int v = arr[L];

        // [L + 1, j] < v ; [j + 1, i) > v;
        int j = L;

        for ( int i = L + 1; i <= R; i++ ) {
            if ( arr[i] < v) {
                // 交換 arr[i] 和 arr [j + 1]
                int tmp = arr[j + 1];
                arr[j + 1] = arr[i];
                arr[i] = tmp;
                j++;
            }
        }
        // 交換 arr[j]  和arr[L]
        int tmp = arr[j];
        arr[j] = arr[L];
        arr[L] = tmp;

        return j;
    }
View Code 快速排序完整代碼

 

 

二、快速排序的優化

1.  快速排序的第一次優化,減小遞歸的深度,轉而使用 選擇排序

    private __quickSorted( int arr[], int L, int R) {

        // if ( (L >= R) {
        //     return;
        // }
        // 快速排序的第一次優化,減小遞歸的深度,轉而使用 選擇排序
        if ( R - L <= 15) { insertSorted(arr, L, R); return; } 
        // 將基點移動到最終位置的方法
        int p = __partioner(arr, L, R);

        // 遞歸拆分數組
        __quickSorted(arr, L, p - 1);
        __quickSorted(arr, p + 1, R);
    }


        // 減小遞歸的深度轉而使用選擇排序
    private void insertSorted(int arr[], int L, int R) { for (int i = L + 1; i <= R; i++) { int i = arr[i]; int j; for (j = i; j > L && arr[j - 1] > e; j--) { arr[j] = arr[j - 1]; } } return; }

 

2. 優化二,基點的選擇隨機化

    private int __partioner ( int arr[], int L, int R ) {

        // 第二次優化,將基點的選擇隨機化
        int rand = (new Random().nextInt(R + 1)) + L; // 交換最左側和隨機點的元素
        int tmp = arr[rand]; arr[rand] = arr[L]; arr[L] = tmp;  
        int v = arr[L];

        // [L + 1, j] < v ; [j + 1, i) > v;
        int j = L;

        for ( int i = L + 1; i <= R; i++ ) {
            if ( arr[i] < v) {
                // 交換 arr[i] 和 arr [j + 1]
                int tmp = arr[j + 1];
                arr[j + 1] = arr[i];
                arr[i] = tmp;
                j++;
            }
        }
        // 交換 arr[j]  和arr[L]
        int tmp = arr[j];
        arr[j] = arr[L];
        arr[L] = tmp;

        return j;
    }

 

三、兩路快排

  解決排序的數組中存在多數重復元素的情況

               

  代碼實現

    public void quickSorted ( int arr[] ) {

        int n = arr.length - 1;            // 閉區間 [0...n]
        __quickSorted (arr, 0, n);
    }

    private __quickSorted( int arr[], int L, int R) {

        // if ( (L >= R) {
        //     return;
        // }
        // 快速排序的第一次優化,減小遞歸的深度,轉而使用 選擇排序
        if ( R - L <= 15) {
            insertSorted(arr, L, R);
            return;
        }


        // 將基點移動到最終位置的方法
        int p = __partioner(arr, L, R);

        // 遞歸拆分數組
        __quickSorted(arr, L, p - 1);
        __quickSorted(arr, p + 1, R);
    }

    private int __partioner ( int arr[], int L, int R ) {

        // 第二次優化,將基點的選擇隨機化
        int rand = (new Random().nextInt(R + 1)) + L;

        // 交換最左側和隨機點的元素
        int tmp = arr[rand];
        arr[rand] = arr[L];
        arr[L] = tmp;

        int v = arr[L];

        // 兩路快排的實現過程
        int i = L + 1;
        int j = R ;

        while (true) {
            while (i <= R && arr[i] < v ){
                i++;
            }
            while (j >= L + 1 && arr[j] > v) {
                j--;
            }
            if (i > j) {
                break;
            }

            // 交換 i 和 j 的位置
            int tmp arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
        int tmp arr[L];
        arr[L] = arr[j];
        arr[j] = tmp;

        return j;
    }

        // 減小遞歸的深度轉而使用選擇排序
    private void insertSorted(int arr[], int L, int R) {

        for (int i = L + 1; i <= R; i++) {
            int i = arr[i];
            int j;
            for (j = i; j > L && arr[j - 1] > e; j--) {
                arr[j] = arr[j - 1];
            }
        }
        return;
    }
View Code 兩路快排代碼實現

 

 

 四、三路快排

                   

代碼實現:

    public static void quickSorted3Ways(int arr[]) {

        int n = arr.length -1;

        // arr[0, n] 閉區間
        __quickSorted3Ways(arr, 0, n);
    }

    private static void __quickSorted3Ways(int[] arr, int L, int R) {

        // if (L >= R) {
        //     return;
        // }
        // 快速排序的第一次優化,減小遞歸的深度,轉而使用 選擇排序
        if ( R - L <= 15) {
            insertSorted(arr, L, R);
            return;
        }

        // 第二次優化,將基點的選擇隨機化
        int rand = (new Random().nextInt(R + 1)) + L;

        // 交換最左側和隨機點的元素
        int tmp = arr[rand];
        arr[rand] = arr[L];
        arr[L] = tmp;
        
        int v = arr[L];
        
        // partioner 
        // 這三個變量的初始值 , 相當重要
        int lt = L;         // arr[L + 1, lt] < v 
        int gt = R + 1;        // arr[gt, R] > v
        int i =L + 1;        // arr[lt + 1, i ) ==v  // 此處的 i 的比較對象
        
        while (i < gt ) {
            if (arr[i] < v) {
                SortedHandler.swap(arr, i, lt + 1);
                lt++;
                i++;
            } else if (arr[i] > v) {
                SortedHandler.swap(arr, i, gt - 1);
                gt--;
            } else {
                i++;
            }
        }
         SortedHandler.swap(arr, lt, L);
         
         __quickSorted3Ways(arr, L, lt -1);
         __quickSorted3Ways(arr, gt, R);
        

    }
View Code 三路快排

 

 

 最后附上整篇 關於快速排序從實現到逐步優化的思路圖 (畫到我懷疑人生了....)

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM