1. 根據快速排序劃分的思想
(1)遞迴對所有資料分成[a,b)b(b,d]兩個區間,(b,d]區間內的數都是大於[a,b)區間內的數
(2)對(b,d]重複(1)操作,直到最右邊的區間個數小於100個。注意[a,b)區間不用劃分
(3) 返回上乙個區間,並返回此區間的數字數目。接著方法仍然是對上一區間的左邊進行劃分,分為[a2,b2)b2(b2,d2]兩個區間,取(b2,d2]區間。如果個數不夠,繼續(3)操作,如果個數超過100的就重複1操作,直到最後右邊只有100個數為止。
2. 維護乙個前100大的小頂堆
(1)先取出前100個數,維護乙個100個數的最小堆,遍歷一遍剩餘的元素,在此過程中維護堆就可以了。具體步驟如下:
(2)取前m個元素(例如m=100),建立乙個小頂堆。保持乙個小頂堆得性質的步驟,執行時間為o(lgm);建立乙個小頂堆執行時間為m*o(lgm)=o(m lgm);
(3)順序讀取後續元素,直到結束。每次讀取乙個元素,如果該元素比堆頂元素小,直接丟棄 如果大於堆頂元素,則用該元素替換堆頂元素,然後保持最小堆性質。最壞情況是每次都需要替換掉堆頂的最小元素,因此需要維護堆的代價為(n-m)*o(lgm);
(4)最後這個堆中的元素就是前最大的10w個。時間複雜度為o(n lgm)。
3. 分塊查詢
先把100w個數分成100份,每份1w個數。先分別找出每1w個數裡面的最大的數,然後比較。找出100個最大的數中的最大的數和最小的數,取最大數的這組的第二大的數,與最小的數比較.。。。
分析:非負整數0~4294967295,注意記憶體限制
1. 用hash儲存
占用記憶體:最壞情況40億*4b=160億b,一般來說是不符合情況的
2. 利用桶的思想:
(1) bit arr=new bit[4294967296];
(2) 在迴圈便利中,將遍歷到的數字的位置的值置為1.如遇到數字256463,則arr[256463]=1
(3)再次遍歷值為0的數字的位置就是沒找到的數。
占用記憶體:8個bit為1b,則長度為4294967295的bit型別的陣列占用的記憶體約為500mb.
3. 分割槽(高階,記憶體限制為10m,但只要求找到其中乙個沒出現過的數即可)
(1)將0~4294967295分為64個區間,每個區間是67108864;int a=new int[64];
(2)遍歷40億的數。如果當前數是3422552090,則a[3422552090/67108864]++
(3)遍歷陣列a,必然會有乙個位置a[i]<67108864,表示這個區間至少有乙個數沒出現過。
(4)再申請乙個長度為67108864長度的bit型別的陣列,bit bitarr=new bit[67108864];
(5)遍歷40億資料,只需要考慮num/67108864==i的num,將bitarr[num%67108864]=1;
(6) 遍歷bitarr陣列,如果bitarr[j]==0,則67108864*i+j則為這樣乙個沒出現過的數。
占用記憶體:64*4b+8m
第一問:
分析:非負整數0~4294967295,注意記憶體限制
1.跟上題類似利用桶的思想,但bitarr的長度為4294967295*2;bit bitarr=new bit[4294967295*2];
2.遍歷40億資料;比如8645231,第一次出現,則標記bitarr[8645231*2]=1,bitarr[8645231]=0,第二次出現bitarr[8645231*2]=0,bitarr[8645231]=1,第三次以及以上出現則標記bitarr[8645231*2]=1,bitarr[8645231]=1
3.以遍歷bitarr陣列,可以找到出現兩次的數。
第二問:
書上思路沒有看懂,下面純屬個人思路,歡迎批評:跟上一題分割槽的思想類似。
(1)將0~4294967295分為2048個區間,每個區間是2097152;int a=new int[2048];
(2)遍歷40億的數。如果當前數是3422552090,則a[3422552090/2097152]++
(3)因為要找40億數的中位數,如果把所有資料排序後,中位數的位置在20億,所以遍歷陣列a,並累加sum=sum+a[i],當sum超過20億時,則中位數在i這個區間
(4)計算中位數在該區間內所有數字累計後 的位置s,然後s=20億 -(sum-a[i]),s代表中位數在i區間內所有數排列後的從前往後第s個數。
(5)再申請乙個長度為2097152長度的int型別的陣列,int bitarr=new int[2097152];
(6)遍歷40億資料,比如遇到num,只考慮num/2097152==i的num,則bitarr[num%2097152]++;
(7)遍歷bitarr,tmp=tmp+bitarr[j],當tmp>=s,則中位數為2097152*i+j.
分析:占用記憶體:2048*4b+2097152*4b~8mb<10mb
大家可能會疑問為什麼一開始可以想到分為2048個區間,我們可以倒推。因為記憶體限制為10mb,我們使用的int型別陣列一條資料就占用4b,則限制資料條數則為10mb/4b=2500000,如果讓資料條數限制在2500000,則資料要分為4294967295/2500000個區間,一般來說都是取2的n次冪,所以取2048.
分析:用hash表來存的話,hash表的key是整數,value是該整數的次數。key是32位整數,需要4b記憶體,哪怕該數出現了20億次也不會溢位的,則value也需要用4b,則一條資料為8b.
如果是2億條資料,則占用記憶體1.6gb,極端情況下有20億條資料,則占用16gb則記憶體不夠用,解決方法是:
(1)把20億條資料的大檔案,用雜湊函式分成16個小檔案,根據雜湊函式的性質,同一種數不可能被雜湊到不同的小檔案上,同時每個小檔案上的資料不會超過2億中,假設雜湊函式足夠好。
(2)對每乙個小檔案用雜湊表來統計其中每種數出現的次數,這樣我們就得到了16個檔案各自出現次數最多的數,才有各自的次數統計,從其中選出次數最多的數即可。
題目補充:每個url占用64b
第一問:
分析:如果直接用hash儲存,則最壞情況下需要記憶體64b*100億=640gb,顯然記憶體太大了。所以還需要將100億條資料的大檔案按照hash函式拆分成小檔案,處理每乙個小檔案,hash表記錄url以及url的數量。當然拆分成多少個小檔案,還得看題目的記憶體要求。這裡就不贅述計算了。可以參考前幾題。
第二問:
分析:根據前一問將大資料檔案拆分後,找到每乙個小檔案 url數量的topk(方法:維持乙個前k大的小頂堆),然後對所有檔案的topk進行外排序或者繼續利用小根堆,找到最終topk.
mysql 大量資料處理問題
一 大量資料儲存問題解決方法 分割槽 分表 原則 多利用點記憶體,減輕磁碟io負載,因為io往往是資料庫伺服器的瓶頸 區別 1,實現方式上 mysql的分表是真正的分表,一張表分成很多表後,每乙個小表都是完正的一張表 分割槽不一樣,一張大表進行分割槽後,他還是一張表,不會變成二張表,但是他存放資料的...
海量資料處理問題
一 給乙個超過100g大小的log file,log中存著ip位址,設計演算法找到出現次數最多的ip位址?該題目要求的是出現次數最多的乙個,有時候題目也會變成求出現次數排名前k的ip位址,兩個問題的解題思路是一致的,只是求前k個會多乙個小步驟,就是建堆,所以現在學習一下,求前k個的思路。100g記憶...
海量資料處理問題
1 給乙個超過100g大小的log le,log中存著ip位址,設計演算法找到出現次數最多的ip位址。如何找到top k的ip 這樣的問題如果出現在資料量較小的情形下,用乙個map或者unordered map都能很快的處理,但是100g這樣的量級放在乙個map裡是絕對不可行的。因此,我們採用雜湊切...