排序算法之——快速排序(Java實現)

        排序算法有很多,今天我來講一講其中實用性最強的一種算法——快速排序。

        爲什麼說它實用性最強呢?因爲快速排序的平均性能非常好,雖然它的最壞運行時間爲O(n^2),但是平均運行時間是O(nlgn),而且裏面隱含的常數因子很小。而且它是原地排序的,所謂原地排序,就是不需要開闢新的數組空間,就可以進行排序。

        快速排序基於分治模式,所謂分治模式,就是把問題拆成一個個小問題,直到問題可以解決。以下是分治過程的三個步驟:

        分解:數組A[p...r]被劃分成兩個子數組(可能空)A[p...q-1]和A[q+1...r],使得前者每個元素都小於等於A(q),後者中的每個元素都大於A(q)。

        解決:通過遞歸調用快速排序,對子數組A[p...q-1]和A[q+1...r]排序。

        合併:因爲兩個子數組是就地排序的,所以合併不需要操作。整個數組A[p...r]已排序。(這裏沒有合併過程,和合並排序有很大不同。關於合併排序


快速排序代碼如下:

    void QuickSort(int[]A, int p, int r){
        if(p < r){
            int q = Partition(A, p, r);
            QuickSort(A, p, q - 1);
            QuickSort(A, q + 1, r);
        }
    }


快速排序的核心是Partition過程,代碼如下:

    /**對子數組A[p...r]進行就地重排
     * @param A
     * @param p
     * @param r
     * @return
     */
    int Partition(int[] A, int p, int r){
        int x = A[r];
        int i = p - 1;
        for(int j = p; j < r; j++){
            if(A[j] <= x){
                i++;
                int temp = A[i];
                A[i] = A[j];
                A[j] = temp;
            }
        }
        int temp = A[i + 1];
        A[i + 1] = A[r];
        A[r] = temp;
        return i + 1;
    }

下面的圖片顯示了Partition在一個包含了八個元素數組上的操作。


所以說,其實數組被分成了四個部分:



以上就是快速排序的內容。比較簡單,圖片來自於《算法導論》


但是!!但是其實有個坑


在做阿里筆試題的時候發現了。尼瑪它的快速排序怎麼感覺和我的不一樣。百度了一下,偶,果然不一樣。。下面這個排序的思路來自數據結構(嚴蔚敏),代碼如下:


    public void qsort(int[] A, int left, int right){
        if(left < right) {
            int key = A[left];
            int low = left, high = right;
            while (low < high) {
                while (low < high && A[high] > key) {
                    high--;
                }
                A[low] = A[high];
                while (low < high && A[low] < key) {
                    low++;
                }
                A[high] = A[low];
            }
            A[low] = key;
            qsort(A, left, low - 1);
            qsort(A, low + 1, right);
        }
    }

這個思路的意思是:先選定左邊爲基準值(你要選右邊也可以,後面代碼相應改一改),定義low,high,然後先從後向前找,如果找到了比基準值小的,則low下標處等於該值,否則high--,然後再從前往後找,如果找到了比基準值大的,則high下標處等於該值,否則low++,直到low和high相等。這道題令人驚奇的是它交換數據的方式:

每個值被覆蓋之前。都被拿走了。首先是基準值,然後之後每個值都是先拿走,然後纔可能被覆蓋,最後再把基準值放到最後一個被拿走的值裏。這樣就實現了一波交換。牛逼啊。


兩個算法大家都要知道,否則以後筆試就會和我一樣坑。

如果對代碼有疑惑可以看我的github源碼,上面有所有方法的單元測試:https://github.com/qjkobe/IntroductionToAlgorithms


如果發現問題,請立刻告訴我。我可不想誤人子弟


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章