快速排序法(詳解)

本文鏈接:https://blog.csdn.net/qq_40941722/article/details/94396010

假設對以下10個數進行快速排序:

6 1 2 7 9 3 4 5 10 8

我們先模擬快速排序的過程:首先,在這個序列中隨便找一個數作爲基準數,通常爲了方便,以第一個數作爲基準數。

6

1

2

7

9

3

4

5

10

8

在初始狀態下,數字6在序列的第1位。我們的目標是將6挪到序列中間的某個位置,假設這個位置是k。現在就需要尋找這個k,並且以第k位爲分界點,左邊的數都\leq6,右邊的數都\geqslant6。那麼如何找到這個位置k呢?

我們要知道,快速排序其實是冒泡排序的一種改進,冒泡排序每次對相鄰的兩個數進行比較,這顯然是一種比較浪費時間的。

而快速排序是分別從兩端開始”探測”的,先從右往左找一個小於6的數,再從左往右找一個大於6的數,然後交換他們。這裏可以用兩個變量iii和jjj,分別指向序列最左邊和最右邊。我們爲這兩個變量起個好聽的名字“哨兵i”和“哨兵j”。剛開始的時候讓哨兵i指向序列的最左邊,指向數字6。讓哨兵jjj指向序列的最右邊,指向數字8。

6 1 2 7 9 3 4 5 10 8
i                 j

首先哨兵j開始出動。因爲此處設置的基準數是最左邊的數,所以需要讓哨兵j先出動,這一點非常重要。哨兵j一步一步地向左挪動(即j=j−1),直到找到一個小於6的數停下來。接下來哨兵iii再一步一步向右挪動(即i=i+1),直到找到一個數大於6的數停下來。最後哨兵j停在了數字5面前,哨兵i停在了數字7面前。

6 1 2 7 9 3 4 5 10 8
      i       j    

現在交換哨兵$i$和哨兵$j$所指向的元素的值。交換之後的序列如下。

6 1 2 5 9 3 4 7 10 8
      i       j    

到此,第一次交換結束。接下來開始哨兵j繼續向左挪動(再友情提醒,每次必須是哨兵j先出發)。他發現了4<6,停下來。哨兵i也繼續向右挪動的,他發現了9>6,停下來。此時再次進行交換,交換之後的序列如下。

 

6 1 2 5 4 3 9 7 10 8
        i   j      

第二次交換結束。哨兵j繼續向左挪動,他發現了3<6,又停下來。哨兵i繼續向右移動,此時哨兵i和哨兵j相遇了,哨兵i和哨兵j都走到3面前。說明此時“探測”結束。我們將基準數6和3進行交換。交換之後的序列如下。

 

3 1 2 5 4 6 9 7 10 8
          i,j        

到此第一輪“探測”真正結束。現在基準數6已經歸位,此時以基準數6爲分界點,6左邊的數都小於等於6,6右邊的數都大於等於6。回顧一下剛纔的過程,其實哨兵jjj的使命就是要找小於基準數的數,而哨兵iii的使命就是要找大於基準數的數,直到iii和jjj碰頭爲止。

現在我們將第一輪“探測"結束後的序列,以6爲分界點拆分成兩個序列,左邊的序列是“3 1 2 5 4”,右邊的序列是“9 7 10 8”。接下來還需要分別處理這兩個序列。因爲6左邊和右邊的序列目前都還是很混亂的。不過不要緊,我們已經掌握了方法,接下來只要模擬剛纔的方法分別處理6左邊和右邊的序列即可。現在先來處理6左邊的序列現吧。

3 1 2 5 4 6        

重複第一輪的過程,應該得到如下序列:

2 1 3 5 4 6        

                
OK,現在3已經歸位。接下來需要處理3左邊的序列:

 

2 1 3     6        

處理之後,2已經歸位,序列“1”只有一個數,也不需要進行任何處理,因此“1”也歸位。

  

1 2 3     6        

對於基數右邊的序列,採用和左邊相同的過程;最終將會得到這樣的序列,如下。

1 2 3 4 5 6 7 8 9 10

細心的同學可能已經發現,快速排序的每一輪處理其實就是將這一輪的基準數歸位,直到所有的數都歸位爲止,排序就結束了。接下來用圖示的方法來展示完整的過程:

在這裏插入圖片描述

 

快速排序之所以比較快,是因爲與冒泡排序相比,每次的交換時跳躍式的,每次排序的時候設置一個基準點,將小於等於基準點的數全部放到基準點的左邊,將大於等於基準點的數全部放到基準點的右邊。這樣在每次交換的時候就不會像冒泡排序一樣每次只能在相鄰的數之間進行交換,交換的距離就大的多了。因此總的比較和交換次數就少了,速度自然就提高了。當然在最壞的情況下,仍可能是相鄰的兩個數進行了交換。因此快速排序的最差時間複雜度和冒泡排序是一樣的都是o(n^{2}),它的平均時間複雜度爲O(\log2 ^{n})

實現快速排序的代碼如下:

void Quick_Sort(int *arr, int begin, int end){
    if(begin > end)
        return;
    int tmp = arr[begin];
    int i = begin;
    int j = end;
    while(i != j){
        while(arr[j] >= tmp && j > i)
            j--;
        while(arr[i] <= tmp && j > i)
            i++;
        if(j > i){
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    }
    arr[begin] = arr[i];
    arr[i] = tmp;
    Quick_Sort(arr, begin, i-1);
    Quick_Sort(arr, i+1, end);
}

 

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