九种排序方法辨析
??????雖然網(wǎng)上有很多關(guān)于排序的文章,但那畢竟是別人。還是決定自己寫一寫,說不定會發(fā)現(xiàn)新的東西。如有錯誤,請務(wù)必指正!
??????目前為止學(xué)過的排序依次包括:冒泡排序,選擇排序,插入排序,希爾排序,快速排序,歸并排序,堆排序,基數(shù)排序,計數(shù)排序。
??????注:在每種排序后都注明該排序方法的穩(wěn)定性。所謂穩(wěn)定性就是排序前后兩個相同元素的位置是否發(fā)生改變。若不變則是穩(wěn)定排序,改變則是不穩(wěn)定排序。規(guī)定本文中所有排序方式為從小到大排序。
1. 冒泡排序(穩(wěn)定排序)
??????冒泡排序的思想是比較兩個相鄰元素,若后面的元素更小則交換兩個元素的位置,以此類推。每次迭代過后,當前序列中最大的元素就被置于末尾。
??????冒泡排序的時間復(fù)雜度是O(n2),最好情況是已經(jīng)有序,時間復(fù)雜度降至O(n)。
代碼如下:
Status Bubble_Sort(int a[MAXSIZE+1]) { int i, j, temp; for (i=1; i<=MAXSIZE; i++) { //注意i, j相差的是一個i for (j=1; j<=MAXSIZE-i; j++) { if (a[j] > a[j+1]) { temp = a[j];a[j] = a[j+1]; a[j+1] = temp; }} } return OK; }2. 選擇排序(不穩(wěn)定排序)
??????選擇排序的思想是比較選擇當前序列中最大的元素與序列中最后一個元素做交換。特點是要保留最大元素的位置。
??????選擇排序的時間復(fù)雜度是O(n2),最好情況是已經(jīng)有序,時間復(fù)雜度降至O(n)。
代碼如下:
3. 插入排序(穩(wěn)定排序)
??????插入排序的思想是,把當前元素與之前的每個元素作比較直至出現(xiàn)當前元素大于之前元素的情況。同時在比較過程中,對比較過但不合適的元素右移。在比較前做一個特殊處理:若當前元素小于前一個元素才進入循環(huán)作比較,否則說明為當前最大直接放在最后即可。
??????插入排序的時間復(fù)雜度是O(n2),最好情況是已經(jīng)有序,時間復(fù)雜度降低至O(n)。
代碼如下:
4. 希爾排序(不穩(wěn)定排序):
??????希爾排序是插入排序的改進算法,調(diào)整了每次前移的距離。并在每輪迭代的時候?qū)⑶耙凭嚯x減少,最終下降至1。特點是需要提前準備好前移序列。
??????希爾排序不穩(wěn)定的原因:一次插入排序是穩(wěn)定的,但多次使用插入排序可能會改變相同元素的相對位置。所以希爾排序是不穩(wěn)定排序。
??????希爾排序的平均時間復(fù)雜度是O(nlogn),不過也取決于前移序列的選擇。上網(wǎng)查閱資料后得知,希爾排序的研究還未停止。時間復(fù)雜度分布在O(nlogn-n2)。
代碼如下:
5. 快速排序(不穩(wěn)定排序):
?????? 快速排序的思想是遞歸選取一個中心點(常選取中心點是序列的第一個元素),將小于中心的值移動到左邊,將大于中心的值移動到右邊。
??????快速排序的平均時間復(fù)雜度是O(nlogn),影響時間復(fù)雜度的是中心點的選取,即左右兩邊的比重。最壞情況是選取一邊沒有元素的中心點,這樣時間復(fù)雜度下降至O(n2)。最優(yōu)情況是選取得中心點恰好是序列的中心點,時間復(fù)雜度為O(nlogn)。可證當選取中心點出現(xiàn)左邊1個,右邊n個的情況時間復(fù)雜度也為O(nlogn)。說明快速排序的壞情況是間隔出現(xiàn)的有兩種方式可以解決這個問題:1.不選取序列第一個元素,改為隨機選取。2.打亂當前序列。經(jīng)過驗證第二種方式的實際效果更好??梢允褂秒S機化算法,先將序列打亂順序再使用快速排序。這樣時間復(fù)雜度可穩(wěn)定在O(nlogn)。
代碼如下:
6. 歸并排序(穩(wěn)定排序):
??????歸并排序的思想是將序列遞歸分治,分解至最小模塊后。不斷歸并有序序列,最終得到整體有序。
??????歸并排序是穩(wěn)定排序的原因:保持歸并排序的穩(wěn)定性可做特殊處理,保證兩組有序序列merge時按照前后兩個序列的先后順序插入即可維持穩(wěn)定。
??????歸并排序的時間復(fù)雜度是O(nlogn)。最好最壞的情況都是O(nlogn)。因為歸并排序?qū)訑?shù)都是logn向下取整。整體merge都是n。特點是比較穩(wěn)定,不受輸入序列順序的影響。但需要O(n)的空間復(fù)雜度。
代碼如下:
7. 堆排序(不穩(wěn)定排序):
??????堆排序思想使用堆的數(shù)據(jù)結(jié)構(gòu)(前面有過專門的文章介紹堆,有需要的朋友可以去看看)。使用最小/大堆,每次將堆頂?shù)脑胤诺胶线m的位置。堆排序共有兩步:將堆頂元素放于合適位置->重新將堆調(diào)整至最小/大堆。
??????堆排序的時間復(fù)雜度是O(nlogn),堆排序的過程包括構(gòu)造堆和取出兩步,最好最壞時間復(fù)雜度都是O(nlogn)。兩者相差是常數(shù)級別。
代碼如下:
8. 基數(shù)排序(穩(wěn)定排序)
??????基數(shù)排序的思想是從最低位開始排序,依次向前移動且不改變相同值的相對位置??梢允褂面湵韥韺崿F(xiàn),留出10個(0,1,。。。9)空間按照最低位放入空間再連接完成一次迭代。
??????基數(shù)排序的時間復(fù)雜度是O(n)。之前很困惑為什么基數(shù)排序的時間復(fù)雜度比快速排序更低,但是卻沒有快速排序常用。經(jīng)過查找資料得出原因:基數(shù)排序的時間復(fù)雜度實際是O(kn)。且常數(shù)K的值往往很大,而快速排序的常數(shù)值很小。并且基數(shù)排序也是相對比較消耗空間的。大多數(shù)應(yīng)用條件下使用快速排序更佳。
代碼如下:
9. 計數(shù)排序(不穩(wěn)定排序):
??????計數(shù)排序的思想是,統(tǒng)計最小元素到最大元素之間每個序列中每個出現(xiàn)的元素個數(shù)并制成表。表中包括每個元素開始的位置,是前一項的起始頂點加前一項的個數(shù)得到。再遍歷一遍原序列,按照表中位置直接插入指定位置。并動態(tài)更新表。
?????? 計數(shù)排序的時間復(fù)雜度是O(n),不過計數(shù)排序只適用于最大元素不是特別大的情況,原因在于需要保留最小元素到最大元素中每一個元素的個數(shù),有的元素個數(shù)為0但仍要占空間。
??????排序方法的選擇更多的是依靠實際序列的特點和規(guī)模。對于規(guī)模變化大的序列排序,可以使用混合的方法,只要計算出臨界值即可。
??????排序真是編程中最基本的操作之一了,不過這么多方法完全弄懂也是有一定難度的。老師說過:對于排序算法要考慮N無窮的情況,切不可貪圖方便只使用O(n2)的方法啦!
因本文作者水平有限,如有問題,請各位高手在下方評論區(qū)指正,謝謝!
總結(jié)
- 上一篇: Linux系统编程:习题,父子进程通过信
- 下一篇: Qt:Qt实现网页自动刷新工具