1. 程式人生 > >演算法:快速排序

演算法:快速排序

轉載地址:https://mp.weixin.qq.com/s/e5iF6zIf_ZpaxkVVANf6nA

 

【資料結構與演算法】 通俗易懂講解 快速排序

 

快速排序介紹

快速排序(Quick Sort)使用分治法策略。它的基本思想是:選擇一個基準數,通過一趟排序將要排序的資料分割成獨立的兩部分;其中一部分的所有資料都比另外一部分的所有資料都要小。然後,再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。

快速排序流程如下:

  • 從數列中挑出一個基準值。

  • 將所有比基準值小的擺放在基準前面,所有比基準值大的擺在基準的後面(相同的數可以到任一邊);在這個分割槽退出之後,該基準就處於數列的中間位置。

  • 遞迴地把"基準值前面的子數列"和"基準值後面的子數列"進行排序。

 

 

快速排序圖文說明

下面以數列a={30,40,60,10,20,50}為例,演示它的快速排序過程(如下圖)。

 

上圖只是給出了第1趟快速排序的流程。在第1趟中流程如下,首先設定基數x=a[i]=a[0],即x=30。

  • 從"右 --> 左"查詢小於x的數:找到滿足條件的 數 a[j]=20,此 時j=4;然後將a[j]賦值a[i],此時i=0;接著從左往右遍歷;

  • 從"左 --> 右"查詢大於x的數:找到滿足條件的數a[i]=40,此時i=1;然後將a[i]賦值a[j],此時j=4;接著從右往左遍歷;

  • 從"右 --> 左"查詢小於x的數:找到滿足條件的數a[j]=10,此時j=3;然後將a[j]賦值a[i],此時i=1;接著從左往右遍歷。

  • 從"左 --> 右"查詢大於x的數:找到滿足條件的數a[i]=60,此時i=2;然後將a[i]賦值a[j],此時j=3;接著從右往左遍歷。

  • 從"右 --> 左"查詢小於x的數:沒有找到滿足條件的數。當i>=j 時,停止查詢;然後將x賦值給a[i]。第一趟遍歷結束!

根據上面的思路,不難寫出下面的快速排序實現:

 

/*
 * 快速排序
 *
 * 引數說明:
 *     a -- 待排序的陣列
 *     l -- 陣列的左邊界(例如,從起始位置開始排序,則l=0)
 *     r -- 陣列的右邊界(例如,排序截至到陣列末尾,則r=a.length-1) */
void quick_sort(int a[], int l, int r)
{    
    if (l < r)
    {        
        int i,j,x;

        i = l;
        j = r;
        x = a[i];        
        while (i < j)
        {            
            while(i < j && a[j] > x)
                j--; // 從右向左找第一個小於x的數
            if(i < j)
                a[i++] = a[j];            
 
            while(i < j && a[i] < x)
                i++; // 從左向右找第一個大於x的數
            if(i < j)
                a[j--] = a[i];
        }
        a[i] = x;
        quick_sort(a, l, i-1); /* 遞迴呼叫 */
        quick_sort(a, i+1, r); /* 遞迴呼叫 */
    }
}

快速排序的時間複雜度和穩定性

快速排序的時間複雜度:快速排序的時間複雜度在最壞情況下是O(N2),平均的時間複雜度是O(N*lgN)。這句話很好理解:假設被排序的數列中有N個數。遍歷一次的時間複雜度是O(N),需要遍歷多少次呢?至少lg(N+1)次,最多N次。

為什麼最少是lg(N+1)次?快速排序是採用的分治法進行遍歷的,我們將它看作一棵二叉樹,它需要遍歷的次數就是二叉樹的深度,而根據完全二叉樹的定義,它的深度至少是lg(N+1)。因此,快速排序的遍歷次數最少是lg(N+1)次。

為什麼最多是N次?這個應該非常簡單,還是將快速排序看作一棵二叉樹,它的深度最大是N。因此,快讀排序的遍歷次數最多是N次。

快速排序的穩定性:快速排序是不穩定的演算法,它不滿足穩定演算法的定義;所謂演算法穩定性指的是對於一個數列中的兩個相等的數a[i]=a[j],在排序前,a[i]在a[j]前面,經過排序後a[i]仍然在a[j]前,那麼這個排序演算法是穩定的。