快速排序的那些事

2021-06-01 00:01:36 字數 2668 閱讀 8781

快速排序是最經典的演算法之一,應用無數,平均時間複雜度(nlgn),最差時間複雜度(n2)。空間複雜度主要看呼叫深度,平均o(lgn),最差o(n)。快速排序的分治思想可以用在很多地方,比如:一堆數中最大的幾個數等。

通常在程式中直接使用庫函式即可,c語言qsort,c++ sort。

用法,void qsort(void *base, int nelem, int width, int (*cmp)(const void *, const void *));

int comp(const void *a,const void *b)

例如:乙個比較整數用的函式,

乙個比較結構體的函式,

int cmp(const void *a, const void *b)

具體呼叫:

int a[n] = ;

qsort(a,10,sizeof(int),comp);

使用方法: sort函式可以傳兩個引數或三個引數。第乙個引數是要排序的區間首位址,第二個引數是區間尾位址的下一位址,排序的區間是 [a,b) 。簡單來說,有乙個陣列 int a[100] ,要對從 a[0] 到 a[99] 的元素進行排序,只要寫 sort(a,a+100) 就行了,預設的排序方式是公升序。

第三個引數是:stl的functional,預設是less,還可以是:

equal_to          相等

not_equal_to    不相等

less                 小於

greater             大於

less_equal        小於等於

greater_equal    大於等於

使用的時候要使用其過載函式,例如: less, greater。

對於使用者的自定義型別,可以定義比較函式,或者過載"

測試一,隨機生成資料,windows xp + vs 2010,在對隨機資料排序時,stl的sort函式的速度要比qsort快。

測試二,對qsort的原始碼修改,它使用了模板,不需要傳入函式指標,而且換掉了原來低效的逐個位元組交換的swap函式,用iter_swap代替。經過對qsort函式進行修改之後,它竟然比sort函式快25.3%!這說明qsort函式的主要開銷在於直接對位元組指標的操作。這同時也說明,對於基本沒有重複鍵的資料來說,qsort比sort要快。

測試三,我們再來比較一下特殊情況。使用系統自帶的srand函式和rand函式,生成0~0x00007fff的數,這樣1000000個數中就會每個數平均有31個重複值。我們看一下執行結果:

qsort     894 ms

m_qsort 519 ms

sort       554 ms

可以清楚地看到,在資料重複比較多的時候,sort的效能明顯得到了提高。

測試四,考慮一種極限情況,所有資料相同,我們修改**再執行一次:

qsort 72 ms

m_qsort 42 ms

sort 24 ms

這次很明顯了,對於重複資料,sort函式的處理能力明顯強於qsort。這主要是和sort函式三路劃分分得更細緻有關。

測試五,我們接著考慮遞增和遞減陣列。修改**然後測試,結果如下:

qsort 497 ms

m_qsort 234 ms

sort 203 ms

sort函式的執行時間比m_qsort要少。我們可以看到,相比隨機資料,有序資料在快速排序的時候得到了很好的優化。再來看遞減的陣列。

qsort 534 ms

m_qsort 261 ms

sort 338 ms

遞減陣列中sort函式略遜於qsort改進版,這大概是因為sort函式取樣9個點造成過多交換開銷造成的。

從整體上看,我們得出這樣乙個結論:對於隨機基本無重複的資料,qsort的改進版比sort函式優秀;而sort函式由於對分割槽比較細緻,所以處理重複資料較多的陣列則會比較優化。

四,快速排序實現的幾個技巧

幾個技巧:

一,quicksort的速度和partitioning element的選取有關係,盡量選取中間值會提高演算法的效率。為了避免最壞情況的發生(對乙個已經排好序的陣列做逆序操作),可以選擇第乙個值,中間值和最後值,三個元素的中間值。(三元素中值法,stl中也使用了這種辦法。)

二,std::sort用的快速排序和插入排序的結合。當元素個數是10~15且基本有序的情況下插入排序的效率較高。當大於這個數字的時候用的是快速排序。實際上快速排序分解成無數個遞迴,演算法的最終必然會變成插入排序。

三,當排序陣列中有大量重複元素的情況下,快速排序效率低。例如:加入陣列中所有元素相等,快速排序掃瞄partition一次,得到的劃分index為1,需要不停地迴圈,效率低下。

通過3路劃分,可以得到以下效果圖,之需要對less和greater部分進行排序即可。

排序穩定性的定義:通俗地講就是保證排序前2個相等的數其在序列的前後位置順序和排序後它們兩個的前後位置順序相同。在簡單形式化一下,如果ai = aj, ai原來在位置前,排序後ai還是要在aj位置前。快速排序是乙個非穩定的排序演算法。例如:序列為 5 3 3 4 3 8 9 10 11, 現在中樞元素5和3(下標從1開始計的第5個元素,出現的第三個3),交換就會把元素3的穩定性打亂(high--,3是其找到的第乙個小於5的元素)。氣泡排序,插入排序都是穩定的排序演算法。

演算法 排序那些事

1 通過比較相鄰兩個元素,把大的元素放在索引大的位置上,這樣比較n 1 i次後,就將最大的元素冒泡到最後面 2 這樣的過程要找n 1次 時間複雜度 最好情況已經排好序o n 最差情況反序o n 2 private static void bubbling int a,int n private st...

remap的那些事

月14日 今天還在看啟動 看到target.c這裡。先說說target.c的職責。target.c檔案包含和目標初始化相關的 如remap設定 系統時鐘設定和儲存器加速模組設定等,以及irq和fiq的異常處理空函式。好吧,這裡 看到了remap就好好查資料把它搞清楚咯!其實我前面看過這個了,只是人上...

AfxWinMain的那些事

afxwinmain函式原形如下 去掉了原來的很多沒用的注釋和累贅 cpp view plain copy print?int afxapi afxwinmain afxwininit函式 建立當前應用程式主線程 initinstance函式 內部通過create 函式來完成視窗的註冊,建立更新和顯...