成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

海量無序數據尋找第 K 大的數

開發 前端
本文簡單介紹了無序數組求 Top K 問題和無序數組求第 K 大數字兩類非常相似的問題,并且提供了常見的三種解決方案。

 

本文轉載自微信公眾號「Kirito的技術分享」,作者kiritomoe。轉載本文請聯系Kirito的技術分享公眾號。

簡單抽象一下問題,便是今天的主題:在一個百萬級無序的 long 數組中,尋找第 K 大的數。要求當然是越快找到越好。

top K 問題

題面一描述出來,很多人都會聯想到 top K 問題,這道題無論是算法領域還是工程領域,都討論的極其廣泛,并且在實際項目中也很容易會遇到類似的問題,我也正好趁著這個機會總結成一篇文章。

常見的 top K 問題,及其變種:

  1. 有 10000000 個記錄,這些查詢串的重復度比較高,如果除去重復后,不超過 3000000 個。一個查詢串的重復度越高,說明查詢它的用戶越多,也就是越熱門。請統計最熱門的 10 個查詢串,要求使用的內存不能超過 1GB。
  2. 有 10 個文件,每個文件 1GB,每個文件的每一行存放的都是用戶的 query,每個文件的 query 都可能重復。按照 query 的頻度排序。
  3. 有一個 1GB 大小的文件,里面的每一行是一個詞,詞的大小不超過 16 個字節,內存限制大小是 1MB。返回頻數最高的 100 個詞。
  4. 提取某日訪問網站次數最多的那個 IP。
  5. 10 億個整數找出重復次數最多的 100 個整數。
  6. 搜索的輸入信息是一個字符串,統計 300 萬條輸入信息中最熱門的前 10 條,每次輸入的一個字符串為不超過 255B,內存使用只有 1GB。
  7. 有 1000 萬個身份證號以及他們對應的數據,身份證號可能重復,找出出現次數最多的身份證號。

傳統 top K 問題的描述:

在海量數據中找出最大的前 K 個數

注意我這次提出的問題和傳統 top K 有一點區別,傳統的 top K 問題要求的一般是”前 K 大的數“,而我現在遇到的是”第 K 大的數“。區別要說大也不大,但對于我們最終選擇的方案可能會有很大的區別。

我下面會介紹一些傳統的 top K 問題的解決思路。并且,按照我一貫的風格,肯定會有代碼放出來,你如果是為了尋找一個”海量無序數據尋找第 K 大的數“問題的答案,相信你可以直接 copy 我的代碼。

方案一:排序法

排序法是最容易想到的思路,復雜度為 O(nlogn) 。能夠想到的各類排序算法呼之欲出,快速排序、歸并排序、插入排序、猴子排序...etc

但是工程領域選擇方案,往往不能僅僅使用算法復雜度來評估:

  • 每個排序方案數據的交換量
  • 額外空間的申請量
  • 平均復雜度
  • 最壞復雜度
  • 不同數據量下的表現

那這個時候有人就要問了,我該如何選擇合適的方案呢?哎,那我又要提到那句話了,benchmark everything!雖然你肯定知道我最終沒有選擇使用排序來解決第 K 大的問題,但我還是想分享給你我的一些測試結論。

在 100w~1000w 數據量級別的無序 long 數組中,JDK 自帶的 Array.sort() 比任何一個排序方案都要快。

Array.sort 的內部實現為 timsort,是一種優化過后的歸并排序。

排序單純靠想也知道不是最優的方案,因為我提出的問題中,僅僅需要找到第 K 大的數,排序方案卻興師動眾把整個數組理順了,沒必要。

方案二:堆

針對一般的 top K 問題,一般都會默認 K 很小,所以一般的 top K 問題,可以選擇使用堆來解決。

堆有個重要的性質:每個結點的值均不大于其左右孩子結點的值,則堆頂元素即為整個堆的最小值。JDK 中 PriorityQueue 實現了堆這個數據結構堆,通過指定 comparator 字段來表示小頂堆或大頂堆,默認為自然序(natural ordering)。

小頂堆解決 Top K 問題的思路:小頂堆維護當前掃描到的最大 K 個數,其后每一次掃描到的元素,若大于堆頂則入堆,然后刪除堆頂;依此往復,直至掃描完所有元素。Java 實現第 K 大整數代碼如下:

  1. public int findKthLargest(int[] nums, int k) { 
  2.   PriorityQueue<Integer> minQueue = new PriorityQueue<>(k); 
  3.   for (int num : nums) { 
  4.     if (minQueue.size() < k || num > minQueue.peek()) 
  5.       minQueue.offer(num); 
  6.     if (minQueue.size() > k) 
  7.       minQueue.poll(); 
  8.   } 
  9.   return minQueue.peek(); 

回到我遇到的問題,求第 K 大的數,這里沒有說明 K 的范圍,那么最壞情況下,K == N/2,無論維護一個 top K 的小頂堆還是維護一個 top(N - K) 的大頂堆,都需要占用 O(N/2) 的內存,而對于海量數據而言,這顯示是一筆非常大的開銷。所以針對我比賽的場景,堆的方案可以直接 pass。

堆的解法適用于 K 較小的場景,而且非常方便維護前 K 個數。

方案三:Quick Select

Quick Select 你可能沒聽過,但快速排序(Quick Sort)你肯定有所耳聞,其實他們兩個算法的作者都是 Hoare,并且思想也非常接近:選取一個基準元素 pivot,將數組切分(partition)為兩個子數組,比 pivot 大的扔左子數組,比 pivot 小的扔右子數組,然后遞推地切分子數組。Quick Select 不同于 Quick Sort 之處在于其沒有對每個子數組做切分,而是對目標子數組做切分。其次,Quick Select 與Quick Sort 一樣,是一個不穩定的算法;pivot 選取直接影響了算法的好壞,最壞情況下的時間復雜度達到了 O(n2)。

在大學參加 ACM 時,我便第一次接觸了該算法,記得那時數據量正好卡的 Quick Sort 無法通過,Quick Select 可以通過。

Quick Select 的 Java 實現如下:

  1. public static long quickSelect(long[] nums, int start, int endint k) { 
  2.         if (start == end) { 
  3.             return nums[start]; 
  4.         } 
  5.         int left = start; 
  6.         int right = end
  7.         long pivot = nums[(start + end) / 2]; 
  8.         while (left <= right) { 
  9.             while (left <= right && nums[left] > pivot) { 
  10.                 left++; 
  11.             } 
  12.             while (left <= right && nums[right] < pivot) { 
  13.                 right--; 
  14.             } 
  15.             if (left <= right) { 
  16.                 long temp = nums[left]; 
  17.                 nums[left] = nums[right]; 
  18.                 nums[right] = temp
  19.                 left++; 
  20.                 right--; 
  21.             } 
  22.         } 
  23.         if (start + k - 1 <= right) { 
  24.             return quickSelect(nums, start, right, k); 
  25.         } 
  26.         if (start + k - 1 >= left) { 
  27.             return quickSelect(nums, leftend, k - (left - start)); 
  28.         } 
  29.         return nums[right + 1]; 

最終,我選擇使用了方案三:Quick Select 作為我求解第 K 大數的方案,也是 benchmark 下來最快的方案。在 10 次查詢中,排序方案耗時為 6s,而 Quick Select 方案,僅需要 300ms,可以說是非常大的優化。

總結

本文簡單介紹了無序數組求 Top K 問題和無序數組求第 K 大數字兩類非常相似的問題,并且提供了常見的三種解決方案。當然,該問題也有很多變種,例如在多核機器,多主機上求解 TopK,甚至可以引入外排和 MapReduce 的思想,其實已經是在考慮其他層面的優化了,我在這里就不過多闡釋了。

 

責任編輯:武曉燕 來源: Kirito的技術分享
相關推薦

2021-07-05 06:39:59

經典算法無序數組

2021-05-17 14:21:48

物聯網數據存儲

2019-10-22 13:54:19

人工智能日志運維

2017-06-02 16:20:51

MapReduceHDFSDedoop

2013-03-26 09:25:51

MapReduceHDFS存儲

2010-04-22 15:34:16

Oracle海量數據

2013-03-01 10:46:50

大數據核心海量數據

2019-08-19 18:42:43

大數據海量數據

2018-11-02 11:03:12

2016-08-08 16:10:10

數據保護存儲

2024-02-21 11:51:11

數據存儲數據壓縮數據管理

2024-01-19 10:50:16

峰會模型

2016-09-01 13:25:20

IBM

2021-03-08 10:18:55

數據庫數據Prometheus

2021-03-15 10:10:29

數據庫數據查詢

2011-04-28 09:36:22

海量數據存儲

2017-11-16 19:26:34

海量數據算法計算機

2011-08-29 14:33:41

2017-11-20 11:37:19

時序數據數據存儲HBase

2017-02-23 10:27:59

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产在线精品一区二区 | 中文字字幕在线中文乱码范文 | 日韩在线综合网 | 色婷婷一区二区三区四区 | 成人一区二区三区在线观看 | 狠狠天天 | 一本大道久久a久久精二百 国产成人免费在线 | 国产在线97| 欧美精品一区二区三区四区五区 | 黄网站在线观看 | 成人老司机 | 久久精品视频网站 | 粉嫩在线| 在线一区视频 | 久久久av| 国产色 | 第一区在线观看免费国语入口 | 一区二区三区久久久 | 亚洲精品一区在线观看 | 狠狠撸在线视频 | 欧美日韩一区二区在线播放 | 日本中文在线 | 欧美国产日韩一区二区三区 | 久久国产精彩视频 | 久久大陆 | 精品亚洲一区二区三区 | 日韩a在线| 国产午夜精品一区二区三区四区 | 精品国产乱码久久久久久a丨 | 自拍偷拍3p | 一级免费毛片 | 欧美日韩成人在线 | 久久69精品久久久久久久电影好 | 很很干很很日 | 国产精品伦一区二区三级视频 | 亚洲一区在线日韩在线深爱 | 精品国产鲁一鲁一区二区张丽 | 成人免费黄色 | jizz视频| 国产95在线 | 国产精品久久久久久久久久久新郎 |