資料結構與演算法學習筆記之程式語言中的排序函式是怎麼實現的
前言
在開發過程中,人人都會用到排序,每種程式語言也會提供排序函式,可是程式語言的排序函式運用環境複雜,必須得達到最大程度的相容。我們得怎麼實現一種通用的,高效的排序函式呢?
正文
1.最通用的排序演算法
如下圖所示:
在我們選取的排序函式中,O(n2)時間複雜度適合小規模的排序,O(nlogn)時間複雜度適合大規模的排序,為了兼顧任意規模,我們選取時間複雜為O(nlogn)的演算法,如:歸併,快排,堆排序。
歸併排序,時間複雜度符合要求,可是他不屬於原地排序演算法,空間複雜度太大,排序1G的資料就需要佔用2G的空間
2.怎麼最佳化快速排序?
快速排序的時間複雜度為O(nlogn),但是在最壞的情況時,我們每次選取的分割槽結點都選擇最後一個資料時,時間複雜都會變為0(n2),那麼最好的分割槽點就是:被分割槽點分開的兩個分割槽中,資料數量差不多。
剛好有兩種簡單常用的分割槽演算法來最佳化:
1.三數取中法
我們從區間的首尾中,分別取出一個資料,然後對比大小,取中間值作為分割槽點。
但是這裡有個弊端:當資料規模太大時,三數取中顯然就不夠了,需要五數取中,甚至十數取中法。
2.隨機發
每次從區間中,選取一個元素作為分割槽點,這種方法並不能保證每次分割槽點都非常好,但是從機率學的角度來看,不太可能會出現每次分割槽點都選的很差的情況,所以這樣分割槽是比較好的。
還有很多的分割槽演算法這裡就不重點敘述了。有興趣的,自己學習一下
3.Java的Sort函式
在各大程式語言中都提供了排序函式,在Java中的sort你閱讀原始碼會發現,
在JDK1.7版本中Arrays.sort()方法是根據傳出引數的長度的大小來判斷用哪種排序方法,一種是針對基本型別的資料,主要是有歸併排序、快速排序、插入排序、計數排序,而另一種則是針對物件型別的排序,改進的歸併排序--合併排序
合併排序是穩定的並且合併排序比較的次數比快排,合併排序的時間複雜度是n*logn, 快速排序的平均時間複雜度也是n*logn,但是合併排序的需要額外的n個引用的空間。排序100M的資料,需要額外100M的空間。
函式中關於閾值的原始碼如下:
/** * The maximum number of runs in merge sort. 合併排序的最大執行次數。 */ private static final int MAX_RUN_COUNT = 67; /** * The maximum length of run in merge sort. * 歸併排序中的最大值,歸併排序是穩定的,時間復 雜度為O(nlogn) */ private static final int MAX_RUN_LENGTH = 33; /** * If the length of an array to be sorted is less than this * constant, Quicksort is used in preference to merge sort. * 快速排序中的最大值,快速排序是不穩定的,時間複雜度為O(nlogn),最壞情況下是O(n^2) */ private static final int QUICKSORT_THRESHOLD = 286; /** * If the length of an array to be sorted is less than this * constant, insertion sort is used in preference to Quicksort. 如果要排序的陣列的長度小於此值 常量,插入排序優先於Quicksort使用。 */ private static final int INSERTION_SORT_THRESHOLD = 47; /** * If the length of a byte array to be sorted is greater than this * constant, counting sort is used in preference to insertion sort. 如果要排序的位元組陣列的長度大於此值 常量,計數排序優先於插入排序。 */ private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29; /** * If the length of a short or char array to be sorted is greater * than this constant, counting sort is used in preference to Quicksort. 如果要排序的short或char陣列的長度更大 比這個常量,計數排序優先於Quicksort使用。 */ private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200;
當排序的資料規模較少時:插入排序優於快速排序
在快排時,其中有一段是:當陣列大小 7<size<=40時,取首、中、末三個元素中間大小的元素作為劃分元。採用的最佳化方案也是三數取中法。
具體的大家可以閱讀原始碼;
4、c語言中qsort()函式
它是一種基於快速排序,歸併排序,插入排序的排序函式
當排序的資料規模很小時,如1k、2k這種我們都是用的歸併排序,雖然歸併排序需要額外的空間,但是這些小規模的資料用遞迴是速度最快的,而且空間消耗我們也負擔得起,這裡就很好的使用空間交換時間的技巧。
當排序的資料規模很大時,原始碼中採用的就是最佳化過的快排,而且最佳化的方法就是“三數取中法”。在使用快排中,當排序的區間中,元素的個數小於等於4時,qsort()就會退化為插入排序,不再使用遞迴來做快速排序,小規模資料面前O(n2)時間複雜度並不一定比O(nlogn)執行時間長。
下圖為y=n2的函式
下圖網上尋找到的y=nlogn與y=n2在一張圖裡的圖片。你會發現O(n2) 比 O(nlogn) 增漲趨勢更猛烈,所以對於小資料量的排序,我們使用比較簡單,不需要遞迴的插入排序
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4328/viewspace-2817393/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料結構學習筆記-堆排序資料結構筆記排序
- 《資料結構與演算法之美》學習筆記之開篇資料結構演算法筆記
- 《資料結構與演算法分析》學習筆記-第七章-排序資料結構演算法筆記排序
- 資料結構與演算法-學習筆記(16)資料結構演算法筆記
- 資料結構與演算法學習筆記01資料結構演算法筆記
- 資料結構與演算法-學習筆記(二)資料結構演算法筆記
- 《資料結構與演算法之美》學習筆記之複雜度資料結構演算法筆記複雜度
- 資料結構與演算法——插入排序以及C++函式模板實現資料結構演算法排序C++函式
- 資料結構與演算法之排序資料結構演算法排序
- 資料結構與演算法分析學習筆記(四) 棧資料結構演算法筆記
- 我是如何學習資料結構與演算法的?資料結構演算法
- 資料結構學習筆記-簡單選擇排序資料結構筆記排序
- 筆記-資料結構之 Hash(OC的粗略實現)筆記資料結構
- 嵌入式C語言中的組成結構是什麼C語言
- 資料結構學習筆記資料結構筆記
- Hark的資料結構與演算法練習之錦標賽排序資料結構演算法排序
- 資料結構與演算法之快速排序資料結構演算法排序
- 【資料結構】 各種排序演算法的實現資料結構排序演算法
- 資料結構筆試題——基於C語言的連結串列功能函式實現資料結構筆試C語言函式
- 資料結構和演算法-學習筆記(一)資料結構演算法筆記
- 資料結構學習筆記-佛洛依德演算法資料結構筆記演算法
- js實現資料結構及演算法之排序演算法JS資料結構演算法排序
- [資料結構與演算法]-排序演算法之插入排序(insertion sort)及其實現(Java)資料結構演算法排序Java
- 資料結構學習筆記--棧資料結構筆記
- 資料結構學習筆記1資料結構筆記
- 演算法與資料結構之原地堆排序演算法資料結構排序
- C語言中抽象函式與具體實現的命名與組織C語言抽象函式
- 【演算法與資料結構專場】堆排序是什麼鬼?演算法資料結構排序
- C#學習筆記--複雜資料型別、函式和結構體C#筆記資料型別函式結構體
- 資料結構與演算法總是不得門而入?來看看我是怎麼學的吧資料結構演算法
- 資料結構之--氣泡排序的三種實現資料結構排序
- c語言學習筆記===函式C語言筆記函式
- 資料結構和演算法學習筆記七:圖的搜尋資料結構演算法筆記
- go 學習筆記之解讀什麼是defer延遲函式Go筆記函式
- dart系列之:dart語言中的函式Dart函式
- 資料結構之---C語言實現快速排序(多個版本)資料結構C語言排序
- 資料結構與演算法——排序資料結構演算法排序
- go 學習筆記之學習函數語言程式設計前不要忘了函式基礎Go筆記函數程式設計函式