快速排序

快速排序是冒泡排序的升級版,都是通過不斷交換數據來進行排序。快速排序的基本思想是:選出一個關鍵字,通過一次遍歷,把比關鍵字小的數據都放到關鍵字左邊,把比關鍵字大的數據都放到關鍵字的右邊。然後在對左右兩邊依次進行快速排序。

由此可以看出,第一步關鍵字的選擇很大程度上決定了快速排序的性能,如果關鍵字剛好選到了在中間左右的數據,那麼經過一次排序後會把整段數據分成兩段基本相等的數據,在進行下去效率就比較高;若果一不小心選擇了最大或者最小的數據,那麼一次排序下來相當於只排好了一個數據,相當不划算。爲了提高性能,通常使用三數取中的方法來選取關鍵字,由於數據是隨機排列的,可以分別在數組的左端、右端、和中間各取一個數,然後把最大的和最小的去掉,留下中間的值作爲關鍵字,三個數同時都取得較大或者較小的概率比較小,因此可以接受。在部分情況下,還會用到九數取中的方法,就是分別取三組三個數,把三組的中數再作比較留下中間的值。

快速排序是一種不穩定的排序,其時間複雜度爲O(nlogn)空間複雜度爲O(logn)~O(n)

//快速排序函數
//L[]爲待排序序列,low爲最低位的下標,high爲最高位的下標
void QuickSort(int L[], int low, int high)
{
    int middle = 0;                   //middle爲關鍵字返回的下標
    while (low < high) {
        middle = Partition(L,low,high);  //把關鍵字排好位置返回其下標
        QuickSort(L, low, middle - 1);       //對關鍵字左邊的部分進行遞歸快速排序
        low = middle + 1;              //對關鍵字右邊的部分進行遞歸快速排序
        
    }
}

//將關鍵字排好順序,這是快速排序中最重要的步驟
//L[]爲待排序序列,low爲最低位的下標,high爲最高位的下標
int Partition(int L[],int low, int high)
{
    int middlekey = 0;
    
    //首先通過三數取中算法得到比較中值得關鍵字
    int m = low + (high - low) / 2;      //計算數組中間元素下標
    if(L[low] > L[high])
    {
        swap(L, low, high);       //保證高位得數比低位的大
    }
    
    if(L[m] > L[high])
    {
        swap(L, m, high);         //保證高位得數比中間的的大
    }
    
    if (L[low] < L[m])
    {
        swap(L, low, m);          //把三個數的中間值放在L[low]的位置上
    }
    
    middlekey = L[low];
    L[0] = middlekey;             //把選出來的中值備份到L[0]的位置上
    while (low < high && L[high] >= middlekey)    //當後面的值一直比中值打,則不用交換,high向前移動
    {
        high--;
    }
    
    //如果跳出while循環則代表高位的值比中值小,把高位的值覆蓋到低位
    L[low] = L[high];             //此函數返回的是中值的下標,因此數據替換掉沒有關係
   
    
    //對低位的處理和高位一樣
    while (low < high && L[low] <= middlekey)
    {
        low++;
    }
    L[high] = L[low];
    L[low] = L[0];
    return low;
    
}

快速排序的時間複雜度:

最壞的情況:所選的關鍵字每次都是最大值或者最小值,這樣的話快速排序就成了冒泡排序,時間複雜度爲O(n^2)

最優/平均情況:第一次調用partition將整個數組掃描一遍,做n次比較。遞歸logn次,所以時間複雜度爲O(nlogn)


空間複雜度:

最壞情況:進行n - 1次遞歸調用,其空間複雜度爲O(n)

平均情況:O(logn)


發佈了28 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章