啊哈算法 之 快速排序

關於效率問題

上篇講的冒泡排序可以說是我們第一個真正的算法,他解決了桶排序的佔用空間過大的問題(因爲桶排序要根據排序的數的個數申請指定的內存),但是冒泡排序卻犧牲了非常大的效率,假設我們要給1億的數進行排序,因爲桶排序的時間複雜度是O(M+N),而冒泡的是O(N2)N的平方,假設計算機的速度是每秒10億次,桶排序只需要0.1秒,而冒泡則需要1000萬秒,大概115天,這是個很恐怖的數字, 想想都能嚇尿人。


基準數

假設我們要對6,1,2,7,9,3,4,5,10,8,這是個數進行排序,我們首先要選個基準數(不要被這個數嚇到,這貨就是我們拿來做參照的),我們就拿6當基準數吧。

排序原理講解

下面我們要把比6大的數的放到6的右邊,把6小的數放到左邊,如何能做到呢,這就要使用上篇冒泡用到的方法,就是進行比較然後交換位置,但是這次我們從兩頭開始,假設有兩個哨兵j和i 。i從6開始,即隊首開始,j從8開始,即隊尾開始,然後兩個哨兵開始向中間尋找大於,小於6的數,哨兵j先出發(爲什麼j先出發呢,大家可以認真想想這個很重要),那麼執行完第一次尋找之後 :3,1,2,5,4,6,7,9,10,8,現在就實現了大於6的在右面,小於的在左邊,6的位置已經確定,接着對6左右兩個分別開始排序(因爲6已經歸位了)左面的選3爲基準數,然後接着從左邊的3,1,2,5,4的五個數組成的隊列的兩頭開始尋找,第一次排序後的結果爲2,1,3,5,4接着以在折半一次進行排序。這樣就達到了最終的排序了,就是一直折半然後隨機選擇一個數當基準數,當然基準數如果靠左,這從右邊開始,如果靠右就從左邊開始,只有這樣才能讓基準數能正確的歸位,這點很重要一定要理解。

關於效率

快速排序之所以快是相比冒泡排序每次交換位置的都是跳躍式的,每次排序設置一個基準數,把小於基準數的放到左邊,大於基準數的放到右邊,這樣就不會像冒泡排序那樣每次只能與相鄰的數進行比較交換位置那麼費事兒,比較的次數少了很多,這樣也就提高了效率。因此冒泡排序最壞的就是相鄰的數進行交換,這樣就和冒泡排序的時間複雜度一致了就是O(N的平方),它的平均時間複雜度是O(nlogN),其實快速排序體現的是一種“二分”思想。好了,下面上代碼讓大家好好理解理解

實例

#include <stdio.h>
int a[101],n;
void quickSort(int left,int right){ //快速排序
    int i,j,t,temp;
    if (left > right) { //判斷參數的正確性
        return;
    }
    temp = a[left];
    i = left;
    j = right;
    while (i != j) { //判斷是否相遇
        while (a[j] >= temp && i < j) { //右邊的是不是小於基準數
            j--;
        }
        while (a[i] <= temp && i < j) { //左邊的是不是大於基準數
            i++;
        }
        if (i < j) { //找到左邊大於基準數,右邊小於基準數進行交換
            t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    a[left] = a[i]; //相遇了,把基準數位置進行調整
    a[i] = temp;
    quickSort(left, i - 1); //遞歸的方法進行基準數左邊的數進行調整
    quickSort(i + 1, right);//遞歸的方法進行基準數右邊的數進行調整
}
int main(int argc, const char * argv[])
{
    int i,n;
    scanf("%d",&n); //輸入數的個數
    for (i = 1; i <= n; i++) { //輸入數據
        scanf("%d",&a[i]);
    }
    quickSort(1, n); //使用快速排序對輸入的數進行排序
    for (i = 1; i <= n; i++) { //輸出排序後的數
        printf("%d ",a[i]);
    }

}

相信大家結合註釋都能看懂代碼,我就不細說了
結果爲:


結果也是能反映俺的代碼沒問題,好了,大家晚安


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