日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

14 | 排序优化:如何实现一个通用的、高性能的排序函数?

發布時間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 14 | 排序优化:如何实现一个通用的、高性能的排序函数? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

問題:平時的開發中,我們都是直接使用這些現成的函數來實現業務邏輯中的排序功能。這些排序函數是如何實現的嗎?底層都利用了哪種排序算法呢?比如 C 語言中 qsort(),C++ STL 中的 sort()、stable_sort(),還有 Java 語言中的 Collections.sort()

希望你把思考的過程看得比標準答案更重要

如何選擇合適的排序算法?

  • 線性排序算法的時間復雜度比較低,適用場景比較特殊。所以如果要寫一個通用的排序函數,不能選擇線性排序算法
  • 如果對小規模數據進行排序,可以選擇時間復雜度是 O(n2) 的算法
  • 如果對大規模數據進行排序,時間復雜度是O(nlogn) 的算法更加高效

總結:為了兼顧任意規模數據的排序,一般都會首選時間復雜度是 O(nlogn) 的排序算法來實現排序函數。堆排序的時間復雜度是 O(nlogn),堆排序和快速排序都有比較多的應用,比如 Java 語言采用堆排序實現排序函數,C 語言使用快速排序實現排序函數。

快排在最壞情況下的時間復雜度是 O(n2),而歸并排序可以做到平均情況、最壞情況下的時間復雜度都是 O(nlogn),為什么歸并排序沒得到普遍的使用?

原因:歸并排序并不是原地排序算法,空間復雜度是 O(n)。所以,粗略點、夸張點講,如果要排序 100MB 的數據,除了數據本身占用的內存之外,排序算法還要額外再占用 100MB 的內存空間,空間耗費就翻倍了

如何優化快排

快排在原數據有序的情況下,如果每次分區點都選擇最后一個數據,那么時間復雜度會退化為O(n2)。實際上,這種 O(n2) 時間復雜度出現的主要原因還是因為我們分區點選得不夠合理。什么樣的分區點合理?

最理想的分區點是:被分區點分開的兩個分區中,數據的數量差不多。比較常用的分區算法:

  • 三數取中法(如果數組較大,可能需要五數取中、十數取中):從區間的首、尾、中間,分別取出一個數,然后對比大小,取這 3 個數的中間值作為分區點
  • 隨機法:每次從要排序的區間中,隨機選擇一個元素作為分區點。不保證每次分區點都選的很好,但是從概率角度推理,不大可能出現每次分區都很差的情況,平均情況下,分區點還是比較好的
  • 快排通過遞歸來實現的,要警惕堆棧溢出。解決方法:一限制遞歸深度,一旦遞歸過深超過閾值,停止遞歸;二是通過在堆上手動模擬一個函數調用棧,手動模擬遞歸壓棧、出棧的過程,擺脫系統棧的大小限制

Glibc 中的 qsort() 函數舉例

源碼分析:

  • qsort() 會優先使用歸并排序來排序輸入數據:因為歸并排序的空間復雜度是 O(n),所以對于小數據量的排序,額外的空間問題不大,通過空間換時間
  • 要排序的數據量比較大的時候,qsort() 會改為用快速排序算法來排序。如何選擇分區點:源碼中采用的是“三數取中法”,另外qsort() 是通過自己實現一個堆上的棧,手動模擬遞歸來解決的
  • qsort() 并不僅僅用到了歸并排序和快速排序,它還用到了插入排序。當要排序的區間中,元素的個數小于等于 4 時,qsort() 就退化為插入排序:因為在小規模數據面前,O(n2) 時間復雜度的算法并不一定比 O(nlogn) 的算法執行時間長
  • 對于小規模數據的排序,O(n2) 的排序算法并不一定比 O(nlogn) 排序算法執行的時間長。對于小數據量的排序,我們選擇比較簡單、不需要遞歸的插入排序算法
  • 此外,在 qsort() 插入排序的算法實現中,也利用了哨兵來簡化代碼,提高執行效率這種編程技巧。雖然哨兵可能只是少做一次判斷,但是畢竟排序函數是非常常用、非常基礎的函數,性能的優化要做到極致

?

總結

以上是生活随笔為你收集整理的14 | 排序优化:如何实现一个通用的、高性能的排序函数?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。