算法之排序(下)

文章來源:http://blog.seclibs.com/算法...算法

前面兩篇文章說了時間複雜度爲O(n2)的冒泡排序、插入排序和選擇排序;也說了時間複雜度爲O(nlogn)的歸併排序和快速排序;此次來講一下時間複雜度爲O(n)的桶排序、計數排序和基數排序,因爲它們的時間複雜度是線性的,因此它們也叫作線性排序(Linear sort),之因此可以作到線性複雜度,是由於它們在排序的時候,不涉及元素之間的比較,同時它們的使用條件也是很是苛刻的。數組

桶排序(Bucket sort)數據結構

桶排序,顧名思義,用桶來對數據進行分割,桶排序是將要排序的數組分到幾個有序的桶裏面,而後對每一個桶裏面的數據進行排序,最後將全部數據依次取出,就完成了排序。spa

來看一下它的時間複雜度,假如將n個數據平均分到m個桶中,每個桶中有x=n/m個數據,每一個桶使用快速排序,時間複雜度爲O(xlogx),m個桶的時間複雜度就是O(m*xlogx),由於x=n/m,因此時間複雜度爲O(nlog(n/m)),當桶的個數接近數據n時, log(n/m) 將會是一個很是小的數,時間複雜度就接近與O(n)了。blog

可是,上面用了假如兩個字,由於要使用桶排序所須要的前提條件比較多,首先數據須要很容易就能夠劃分到m個桶中,並且每個桶它自己就須要有前後順序,這樣桶就不須要再進行排序了。其次,咱們上面把均勻兩個字給加粗了,只有在桶中的數據比較平均時才能夠,若是每個桶中的數據差距是很是大的,那桶內排序的時間複雜度就不是常量級了,最極端的狀況就是分到了一個桶中,那時間複雜度就變成了O(nlogn)了。排序

桶排序比較適合用在外部排序中。所謂的外部排序就是數據存儲在外部磁盤中,數據量比較大,內存有限,沒法將數據所有加載到內存中。內存

假若有10個G的訂單數據,訂單金額都是正整數,要根據金額大小進行排序,而內存又比較小,沒法同時裝下全部的數據該怎麼辦?rem

用桶排序的思路就是,先掃描一遍訂單,看一下大概的金額分佈,假如金額都分佈在1到1萬,咱們就能夠將金額分到10個桶裏,第一個桶是1~1000,依此類推,它們的順序依次是0,1,2…9。文檔

理想狀況下,就是它們均勻分佈在每個桶中,而後咱們在每個桶中使用快速排序,最後將它們依次輸出出來。那若是1000-2000的金額比較多的話,仍是沒法直接放到內存中,那就繼續使用桶排序進行分割,直到所有排序完成。字符串


計數排序(Counting sort)

計數排序基本上屬於桶排序的特殊狀況,在要排序的範圍不大的時候,好比有x個數據,那咱們就分x個桶,每一個桶內的數據都是相同的,這樣咱們就省下了桶內排序的時間。

至於爲何要叫計數,這個是跟計數排序的實現方法有關的,不過我尚未理解清楚,這裏就先放下了,這個坑以後再填。


基數排序(Radix sort)

再來一個排序問題來看,若是有十萬個手機號碼,要將這十萬個手機號從小到大排序。若是使用前面的桶排序和計數排序,它的範圍比較大,這兩種算法明顯都不適合。

如今就能夠用到第三個排序方法,基數排序。在剛剛的問題裏,咱們能夠明顯的看出來,當一個號碼前面的幾位已經明顯大於另外一個號碼,那後面的也就不須要比較了,也就是說咱們須要將手機號排序爲第一個數字從小到大排序,第一個數字相同的,按照第二個數字從小到大排序,第二個數字相同的,按照第三個,依此類推,那如何才能排列成這樣呢。

這裏咱們用一個新的思路來考慮,咱們先按照最後一位數字的大小來進行排序,而後再按照倒數第二位進行排序,依此類推,通過11次排序之後,就完成了對整個手機號的排序。這裏須要注意一下的是,必須用穩定的排序算法來實現,若是是非穩定的排序算法,以前的排序就沒有任何的意義了。

用幾個字符串表示的話,就是這個樣子的

再舉一個訂單的例子,對於一批訂單,咱們但願將它按照金額的大小排序,若是金額相同,就按照下單的時間進行排序,同樣是使用這樣的方法。

那若是咱們須要排序的數據並非等長的,又該如何去處理,好比說要對單詞進行排序,有的單詞是五個字母,有的單詞是十五個字母,那該如何處理?

咱們能夠把全部的字母都補到同樣的長度,不足的後面補0,由於根據ASCII碼咱們能夠發現,全部的字母都在數字0以後,它並不會影響排序的正常進行,因此依舊可使用基數排序來進行。


參考文檔

極客時間-數據結構與算法之美

文章首發公衆號和我的博客

公衆號:無意的夢囈(wuxinmengyi)

博客:http://blog.seclibs.com/

相關文章
相關標籤/搜索