排序算法階段總結(二)——如何選擇合適的算法

當數據符合線性排序對數據的要求

當數據符合線性排序的要求時,優先使用線性排序。時間複雜度爲O(n)。

但是對於大多數情況下,數據並不一定符合線性排序的數據要求。

 

小規模數據

如果對於小規模的數據排序,我們可以選擇時間複雜度是 O(n²) 的算法。

因爲在小規模數據面前,O(n²) 時間複雜度的算法並不一定比 O(nlogn) 的算法執行時間長。

我們通常進行的複雜度分析是偏理論的,大部分使用大O漸進複雜度表示。實際上時間複雜度並不等於代碼實際的運行時間。

時間複雜度代表的是一個增長趨勢,如果畫成增長曲線圖,會發現 O(n²) 比 O(nlogn) 要陡峭,也就是說增長趨勢要更猛一些。

在大 O 複雜度表示法中,我們會省略低階、係數和常數。

也就是說,O(nlogn) 在沒有省略低階、係數、常數之前可能是 O(knlogn + c),而且 k 和 c 有可能還是一個比較大的數。

假設 k=1000,c=200,當我們對小規模數據(比如 n=100)排序時,n2的值實際上比 knlogn+c 還要小。

knlogn+c = 1000 * 100 * log100 + 200 遠大於10000

n^2 = 100*100 = 10000

 

大規模數據

如果對大規模數據進行排序,時間複雜度是 O(nlogn) 的算法更加高效。對於大規模數據,使用O(n²)的算法效率並不高。

所以,爲了兼顧任意規模數據的排序,一般都會首選時間複雜度是 O(nlogn) 的排序算法來實現排序函數。

時間複雜度是 O(nlogn) 的排序算法有快速排序和歸併排序,還有一個堆排序,快速排序和堆排序都有很多的應用。

但是,同爲O(nlogn) 的排序算法的歸併排序使用的並不多。那爲什麼呢?

快速排序當分區點選擇極其不合理的時候,快速排序的最壞情況下時間複雜度爲O(n²)。

而歸併排序能做到最好、最壞平均情況下複雜度都爲O(nlogn)。

主要原因是歸併排序是一個非原地排序算法,空間複雜度爲O(n)。

如果要排序 100MB 的數據,除了數據本身佔用的內存之外,排序算法還要額外再佔用 100MB 的內存空間,空間耗費就翻倍了。這就是歸併排序相對於快速排序來講最大的缺點。

快速排序的最壞情況下時間複雜度爲O(n²),這種 O(n²) 時間複雜度出現的主要原因還是因爲我們分區點選的不夠合理。

我們可以通過優化快速排序來規避這種情況,來選擇儘可能合理的分區點。如隨機法、三/五/十數取中法

 

舉例

C語言中的 qsort()。

從名字上看,很像是基於快速排序算法實現的,實際上它並不僅僅用了快排這一種算法。

在源碼中,qsort() 會優先使用歸併排序來排序輸入數據。

因爲歸併排序的空間複雜度是 O(n),所以對於小數據量的排序,比如 1KB、2KB 等,歸併排序額外需要 1KB、2KB 的內存空間,這個問題不大。現在計算機的內存都挺大的,我們很多時候追求的是速度。這就是一個典型的用空間換時間的應用。

如果數據量太大,排序 100MB 的數據,這個時候我們再用歸併排序就不合適了。

所以,要排序的數據量比較大的時候,qsort() 會改爲用快速排序算法來排序。

qsort() 選擇分區點的方法就是“三數取中法”。

qsort() 並不僅僅用到了歸併排序和快速排序,它還用到了插入排序。

在快速排序的過程中,當要排序的區間中,元素的個數小於等於 4 時,qsort() 就退化爲插入排序,不再繼續用遞歸來做快速排序

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章