TopN問題
這種問題首先排序壹定能解決,例如快速排序或者冒泡排序,這裏如果實用排序算法來實現的話冒泡排序可能要優於快速排序(因此只需要找出前100或者前1000大的數即可,即使使用冒泡排序也只需要冒泡100次或者1000次即可,算法的時間復雜度是100N或者1000N,而使用冒泡排序的時間復雜度是Nlogn)。
無論是什麽排序都可以實現TopN的問題,但是時間復雜度相對較高,因此可以考慮分治的思想與快速排序相結合,首先類似於快速排序算法,從中任選壹個數作為標兵,然後對整個集合進行partition分區,將大於它的至於左邊,小於它的至於右邊如下圖所示。
如果前壹部分的集合的長度等於N排序結束,如果前壹部分的集合的長度大於N,則從前壹部分中在隨機查找出壹個數作為標兵,對該集合做partition分區操作;如果該集合的長度小於N,對小於標兵T2的集合做partition分區操作,判斷右邊大於T2的集合是否等於N-S(num>T1),以此類推
這樣的話算法的時間復雜度是O(N)。
因為第壹次做partition的時間復雜度壹定是O(N),第二次來看數據已經減半了,以此類推,因此總的時間復雜度為O(N) = N + N / 2 + N / 2^2 +N / 2^3 +...,因此總的時間復雜度是O(N)。
實現分治算法的前提是需要有足夠的內存空間,如果內存空間不夠,例如只有2G的內存空間,而以Int32位來計算,10億個數需要4G的內存空間開存儲,現在不滿足條件,這時就需要使用文件分別存儲,
第二次再從其中壹個文件中讀取數據,這樣的話也是可以實現的,但是缺點是需要多次磁盤的讀取和寫入操作,效率相對不高。
使用如果內存不足的情況下使用文件操作效率較低,因此可以考慮分布式計算,例如有1000臺電腦,每壹臺電腦計算1百萬個數中的前1000大的數,然後將這1000*1000大的數再進行排序也能實現需求,這樣的好處是計算較快,缺點也很明顯,需要1000臺電腦。
如果只有壹臺電腦的時候,可以考慮使用堆排序,首先先內存中開辟出壹個容量為壹千的小頂堆,然後將數組中的前1000個數據放入小頂推中並排序,根據堆的性質,堆中的每壹個元素都比它的左右子節點中的元素小。後面每次進入的數堆排序字對進行壹次堆排序,如果插入的元素比堆頂的元素小則直接丟棄,否則將堆頂元素替換並進行堆排序,從新構成小頂堆,以此類推。當所有的數據都處理完後,剩下的堆中的元素就是所要的10億元素中最大的前1000個數。最後以此輸出堆中元素。
這種方式的優點是所有的元素都只讀區壹次。不存在數據多次讀取的情況。