常用演算法之排序演算法三【快速排序】

來源:互聯網
上載者:User

標籤:排序演算法   快速排序   

快速排序是東尼·霍爾在1962提出的劃分交換排序,並採用一種分治的策略。在這,我們先總結一下:快速排序 = 劃分交換排序 + 分治。然後我們在一一介紹他。

劃分交換排序

在討論它時,感覺有種看了崔顥《黃鶴樓》之後,再去寫黃鶴樓的感覺,因為MoreWindows寫 得白話經典演算法系列之六 快速排序 快速搞定已經足夠出色了。我在這隻是進行簡單的複述,你需要瞭解更多請看他的博文。

先來看看劃分交換排序的具體演算法描述:

1.從數列中選出一個數作為基準

2.從數組中選出比它大的數放右邊,比它小的數放左邊

3.重複以上操作,直至只剩最後一個數

看了演算法描述呢,感覺還是有點晦澀,我們可以換過一種思考方式:挖坑填數。

我們先來看看具體執行個體:

給出一個數組,並將第一個數作為基準

 0

  1

2

3

4

5

6

7

8

9

72

6

57

88

60

42

83

73

48

85


初始化時,i = 0, j = 9; X = array[0] = 72

由於array[0] 已經儲存到X中,所以,可以理解已經在i = 0處,挖好了一個坑,可以將其他的資料填充到這個坑中。

接下來充由j位置從後往前進行尋找小於等於基準的值,在j = 8處48符合條件,這時我們將它挖出,並填到上一個坑處,即array[0] = array[8];i++;此時,我們填好了一個坑,但是又重建了一個新坑,該怎麼辦呢。我們依舊需要找一個其他的值將它填上,接下來我們在i的位置從前往後找,直至找到大於等於基準的值。當i = 3;時,符合條件,將array[8] = array[3];j--;數組便變成了:

0

 1

2

3

4

5

6

7

8

9

48

6

57

88

60

42

83

73

88

85


此時i = 3, j = 7

重複以上操作,先從後往前找,在從前往後找。

從j開始往前找,在j = 5處的42小於基準值,將它填到i = 3處,array[3] = array[5]; i++;

從i = 4處開始從前往後找,當i = 5時依舊沒有合格值,且(i<j)不滿足,所以應該跳出迴圈,退出。

此時 i=5,且j = 5,整個數組剩下一個坑就是i = 5時,因為第一次的劃分已經完畢,所以講基準值填回坑中,即array[i]=X;


數組變成:

0

 1

2

3

4

5

6

7

8

9

48

6

57

42

60

72

83

73

88

85


可以看出,i=5之前的值全部小於或等於array[5],之後的值大於等於array[5]。

請注意,不是每次的劃分都會是這麼理想,當所以怎麼選擇基準會成為影響效率的一大原因,其次因為每次是找出大於等於或小於等於的值進行填坑,所以該演算法是不穩定的。

接下來,我們將數組分為兩個集合p1 = array[0...4], p2 = array[6...9],那麼我們先來看看這段思想化成的代碼吧。

    public static void sort(int[] array, int left, int right){        int i = left;        int j = right;        if (i >= j){            return;        }        int pivot = array[i];        while (i < j){            while ((i < j) && (array[j] > pivot)){                j--;            }            if (i < j){                array[i] = array[j];            }            while ((i < j) && (array[i] < pivot)){                i++;            }            if (i < j){                array[j] = array[i];            }        }        array[i] = pivot;   }


然後再劃分好之後繼續如此,直至集合中元素小於等於1個,好好想想,這個有沒有像什麼,沒錯,樹,小的放左邊,大的放右邊,依照方法想,我們可以想到遞迴。好了下來,就是我們的分治了。

分治法

  在這,不做詳細的介紹,假如有興趣,推薦部落格 五大常用演算法之一:分治演算法。

分治演算法最簡單的解釋就是:將一個問題分解成多個小問題,再遞迴解決所有的問題,最後將解合并,產生最終解。

他的演算法模式:

    Divide-and-Conquer(P)    1. if |P|≤n0    2. then return(ADHOC(P))    3. 將P分解為較小的子問題 P1 ,P2 ,...,Pk    4. for i←1 to k    5. do yi ← Divide-and-Conquer(Pi) △ 遞迴解決Pi    6. T ← MERGE(y1,y2,...,yk) △ 合并子問題    7. return(T)
  分治在快排中的具體思想:

在一個給定的一個數組R[left....right]中,先從數組中選取一個元素作為基準pivort,根據基準,可以將數組分為兩個子數組R[left....pivortpos-1]和R[pivortpost+1....right]。根據定義,可以知道,左邊的元素全部小於等於基準pivort,右邊的元素全部大於等於pivort,所以pivort已經在正確的位置上了,在接下來的遞迴中,不需要在對它進行劃分。

劃分的關鍵是求出基準所在的位置pivortpos,劃分的結果可以簡單表示為pivort = R[pivortpos];換分的結果可以簡單表示為:

R[left...pivortpos-1] <= pivort <= R[pivortpos+1....right]

left <= pivortpos <= right

所以在我們可以寫出分治的部分代碼

    public static void sort1(int[] array, int left, int right){        if (left >= right){            return;        }        int i = left;        int j = right;        int pivort = array[i];        while(i < j){            //劃分交換            int pivortpos = Partition(R, left, right);            sort(array, left, pivortpos-1);            sort(array,pivortpos+1, right);        }    }

所以,我們可以將兩個代碼結合,得到完整的代碼:

    public static void sort(int[] array, int left, int right){        int i = left;        int j = right;        if (i >= j){            return;        }        int pivot = array[i];        while (i < j){            while ((i < j) && (array[j] > pivot)){                j--;            }            if (i < j){                array[i] = array[j];            }            while ((i < j) && (array[i] < pivot)){                i++;            }            if (i < j){                array[j] = array[i];            }        }        array[i] = pivot;        sort(array, left, i-1);        sort(array, i+1, right);    }
說完了,但是可能還是感覺有點不清楚,那我們繼續來看一下他的執行過程:

首先可以大家可以先看個動畫示範,是關於劃分交換的,當然假如你覺得自己足夠清楚,可以跳過;
假如我們存在以下集合:



在這我們可以看到,他並不是穩定的排序演算法,並且他的效率和基準的選擇有很大的關係。

總結:

快速排序的最壞時間複雜度是O(n^2),最好時間複雜度為O(nlogn),平均時間複雜度為O(nlogn),他是基於關鍵字比較的內部排序演算法中速度最快的。

空間複雜度:因為是遞迴樹的高度O(logn),所以需要棧空間O(logn),最差時是O(n)。

常用演算法之排序演算法三【快速排序】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.