各大排序演算法優缺點總結
我這裡只總結各大演算法知識的要點,如果你想看看演算法思想和實現程式碼,網上的其他部落格都很喜歡貼大段程式碼和文字,可以自己去看。
(如果出錯,請指正!感激不盡!)
一.三大簡單、慢速排序演算法
平均 |
最好 |
最壞 |
輔助儲存 |
穩定性 |
|
直接插入 |
n^2 |
n |
n^2 |
1 |
穩定 |
直接選擇 |
n^2 |
n^2 |
n^2 |
1 |
不穩定 |
直接交換(冒泡) |
n^2 |
n |
n^2 |
1 |
穩定 |
我省略了O,如:上面的n^2其實是O(n^2)的意思
這三種演算法的有點都是簡單,缺點都是慢。
優點 |
缺點 |
直接插入 |
比較次數越少,移動次數越多 |
直接選擇 |
|
直接交換(冒泡) |
每次只移動相鄰兩個元素 |
二.希爾排序
n^1.3 n n^2 1 不穩定
希爾排序中,演算法的效率很大程度由增量決定,而一個合適的增量的選擇需要大量的經驗。
三.堆排序
nlog2n nlog2n nlog2n 1 不穩定
nlog2n的2是下標,在這裡不知道怎麼設定,大家應該瞭解。
它比快速排序的優點:在最壞情況下它的效能很優越
它比歸併排序的有點:使用的輔助儲存少
它的缺點: 不適合太小的待排序列(因為他需要建堆);不穩定,不適合物件的排序
四.快速排序、歸併排序(最常用的排序演算法)
平均 |
最好 |
最壞 |
輔助儲存 |
穩定性 |
|
快速排序 |
nlog2n |
nlog2n |
n^2 |
1 |
不穩定 |
歸併排序 |
nlog2n |
nlog2n |
nlog2n |
n |
穩定 |
(分治法思想)
PS:二者各自的特點。
快速排序最快的排序演算法,缺點是不穩定,不適合物件排序;
歸併排序第二塊的演算法,缺點是輔存很大,適合物件排序;
PS:快速排序遞迴堆疊空間的佔用:
最優的情況下空間複雜度為:O(logn) ;每一次都平分陣列的情況
最差的情況下空間複雜度為:O(n );退化為氣泡排序的情況
PS:一個排整數的測試:
在筆記本上跑的,對1024*1024個隨機整數排序,快速排序比合並排序快3到4倍。
[05.0813:40:22] INFO: Performance Check: Quick Sort 1048576 Elements., took 94 ms
[05.0813:40:22] INFO: Performance Check: Merge Sort 1048576 Elements., took 437 ms
五.以Java 集合類的sort()排序為例子(jdk不同版本sort()實現也不同)
1.JDK6中的排序是基於傳統的歸併排序做了部分優化,這兩個優化都很簡單,實際上效率並未提高多少。所以在JDK7中將其替換為TimSort。
2.JDK 7中,內部實現換成了TimSort,其對物件間比較的實現要求更加嚴格,
(1)傳入的待排序陣列若小於閾值MIN_MERGE(Java實現中為32,Python實現中為64),則呼叫binarySort,這是一個不包含合併操作的 mini-TimSort。二分查詢/折半插入查詢,
從陣列開始處找到一組連線升序或嚴格降序(找到後翻轉)的數。
(2)否則, 不斷二分,直到小於閾值,然後插入排序;
TimSort演算法是一種起源於歸併排序和插入排序的混合排序演算法
3.在jdk8中,如果你看過原始碼就會知道,其實針對不同的情況使用了不同的排序演算法,簡單羅列下:
(1).如果是簡單物件資料,例如int,double,且陣列長度在一定閥值內,則使用快排,如果在閥值外,則用歸併的變種;
(2).如果是複雜物件陣列,則如果陣列長度在一定閥值以內,則使用折半插入排序,如果長度在閥值外,則使用歸併法,但是如果歸併二分後小於閥值了,則在內部還是會使用折半插入排序。。。以上只是大概
大家一定注意到了,閾值以外需要使用歸併,因為快排使用遞迴,如果待排序列太大的話,堆疊可能會溢位;而歸併排序不存在此問題;
我查閱了jdk8的新功能,其中好像並沒有關於sort()的更新,這樣說來,jdk7和8應該在sort()上沒有區別才對;但是我在知乎上找到了關於jdk8 的sort()描述,好像還有很多人同意的樣子,所以我就把他的言論給貼了過來。
後來這一塊還是沒弄明白,發了個求助的帖子,有了結果後,我會修改這個博文的。若是有高手看到此處,還望不吝賜教啊!