常见排序算法的时间复杂度汇总
非線性排序
通過比較來決定元素間的相對次序,由于其時間復雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。
| 選擇排序 | O(N^2) | O(N^2) | O(N^2) | 不穩定 | O(1) |
| 插入排序 | O(N) | O(N^2) | O(N^2) | 穩定 | O(1) |
| 冒泡排序 | O(N) | O(N^2) | O(N^2) | 穩定 | O(1) |
| 希爾排序 | O(N) | O(N^(3/2)) | O(N^S)(1<S<2) | 不穩定 | O(1) |
| 快速排序 | O(NlogN) | O(NlogN) | O(N^2) | 不穩定 | O(logN) |
| 堆排序 | O(NlogN) | O(NlogN) | O(NlogN) | 不穩定 | O(1) |
| 歸并排序 | O(NlogN) | O(NlogN) | O(NlogN) | 穩定 | O(N) |
注:logN表示以2為底N的對數。
穩定性:待排序數據中有相同的數,排序之后相同的數與排序前的前后位置關系不變,則成為穩定排序算法。比如我們有一組數據2,9,3,4,8,3;按照大小排序之后就是2,3,3,4,8,9;兩個3的前后順序在排序前后保持不變,即穩定。
為什么要考察穩定性?
答:實際的開發任務中,并不是單純的對數字進行排序,而是對象,需要根據對象的某個key進行排序。舉個例子:現在要給電商交易系統中的“訂單”排序。訂單有兩個屬性,一個是下單時間,另一個是訂單金額。如果我們現在有10萬條訂單數據,我們希望按照金額從小到大對訂單數據排序。對于金額相同的訂單,我們希望按照下單時間從早到晚有序。
最先想到的方法是:我們先按照金額對訂單數據進行排序,然后,再遍歷排序之后的訂單數據,對于每個金額相同的小區間再按照下單時間排序。這種排序思路理解起來不難,但是實現起來會很復雜。
借助穩定排序算法,這個問題可以非常簡潔地解決。解決思路是這樣的:我們先按照下單時間給訂單排序,注意是按照下單時間,不是金額。排序完成之后,我們用穩定排序算法,按照訂單金額重新排序。兩遍排序之后,我們得到的訂單數據就是按照金額從小到大排序,金額相同的訂單按照下單時間從早到晚排序的。為什么呢?
穩定排序算法可以保持金額相同的兩個對象,在排序之后的前后順序不變。第一次排序之后,所有的訂單按照下單時間從早到晚有序了。在第二次排序中,我們用的是穩定的排序算法,所以經過第二次排序之后,相同金額的訂單仍然保持下單時間從早到晚有序。
1 選擇排序
2 插入排序
3 冒泡排序
4 希爾排序
5 快速排序
以下為第一趟排序,基值為30,讓小于30的所有數據在30左邊,大于30的數據在30的右邊,然后遞歸分別對30左邊和右邊的數組進行相同的操作。
6 堆排序
通常用于求top K問題
這個用圖看不清楚,看這個鏈接吧
7 歸并排序
要理解和學會歸并的思想
線性排序
不通過比較來決定元素間的相對次序,它可以突破基于比較排序的時間下界,以線性時間運行,時間復雜度都可以趨近于O(N),因此稱為線性時間非比較類排序。 只適用于一些特定的場合。
8 桶排序
核心思想是:將將要排序的數據分到幾個有序的桶里,每個桶里的數據再單獨進行排序。桶內排完序之后,再把每個桶里的數據按照順序依次取出,組成的序列就是有序的了。舉個簡單的例子:
每個桶內進行快速排序后,根據桶的編號匯總數據即可。
使用要求:
- 需要能很方便的將數據劃分成m個桶
- 桶之間無需排序
- 數據要盡量分布均勻
使用場景:適合于外部排序。所謂外部排序就是數據存儲在外部磁盤中,數據量比較大,內存有限,無法將數據全部加載到內存中。MySQL在排序的時候如果內存不夠,就會使用外部排序,把數據分成多份,每份單獨排序后寫入臨時文件,最后把這些有序的文件合成一個大文件。其通常采用的是歸并排序算法。
比如說我們有10GB的訂單數據,我們希望按訂單金額(假設金額都是正整數)進行排序,但是我們的內存有限,只有幾百MB,沒辦法一次性把10GB的數據都加載到內存中。這種情況就可以使用桶排序:
9 計數排序
可以認為是桶排序的特殊情況:要排序的數據的范圍不大的情況,假設范圍是0到k,那么計數排序就是直接分配k+1個桶,每個桶內的數值都是相等的,省掉了桶內排序的過程。
舉個例子:假設某省50萬考生,需要根據成績排序。成績的范圍是0-750,那么就可以申請一個長度為751的數組,下標對應分數0到750。遍歷這50萬的數據,對應分數上統計數量。最后只需要依次遍歷這個數組:假設下標為0(即分數為0)的統計有100個,那么直接輸出100個0;下標為1的有3個,那么再往后追加輸出3個1;……直到下標為750,即可完成排序。因為只涉及掃描遍歷操作,所以時間復雜度是O(n)。
使用場景:只能用于數據范圍不大的情況,且數據都是正整數的情況(如果不是,需要先進行處理)。
備注:最終完成排序的數組,也可以使用前綴和的方式來實現,這個方法有點繞,有興趣的可以自己百度了解下。
10 基數排序
原理是將整數按位數切割成不同的數字,然后按每個位數分別歸類。由于整數也可以表達字符串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是只能使用于整數。
舉個例子:給10萬個手機號碼從小到大排序。
借助于穩定排序算法,從后往前,對手機號碼的每一位進行穩定排序,如可以使用桶排序或者計數排序,即先對所有手機號的第10位進行桶排序,再對第0位……直到第0位。每次桶排序的時間復雜度為O(N),假設要進行k次排序,則基數排序的時間復雜度為o(kN)。由于手機號通常是11位,所以這里時間復雜度為O(11N),近似O(N)。
此外,如果待排序的字符串的長度不一致,可以先補"0",因為根據ASCII值,所有字母都大于“0”,所以補“0”不會影響到原有的大小順序。這樣就可以繼續用基數排序了。
總結
以上是生活随笔為你收集整理的常见排序算法的时间复杂度汇总的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#和其它C语言的区别
- 下一篇: 使用session保持登录状态,cook