乙個金山的筆試題:
有乙個日誌檔案,每行記錄了一次呼叫資訊,其中包括時間和**
ip。每天的記錄數目大約
10億條左右。現在需要:
1)獲取日訪問次數最高的
1000
個**ip
,按照訪問量從高到低排序。
2)獲取連續一周內訪問次數最高的
1000
個**ip
,按照訪問量從高到低排序。
請給出能得到精確(非近似)結果,並且效率盡可能高的計算方法,並給出主要部分偽**。
大資料量的問題,面臨以下幾個問題:一、該
10億條資料中最多有多少條
ip記錄。考慮是否可以一次將記錄讀入記憶體,進行排序
二、ip
記錄過大,無法完全讀入記憶體,則考慮外部排序。
三、考慮演算法的優化,效率問題
四、根據實際的問題,分析考慮如何實現該演算法。
五、是否可已匯入資料庫,使用資料庫操作來實現(其實大部分公司,對日誌的分析,都是匯入的資料庫中進行,並優化資料庫操作,減低資料庫壓力)
l不考慮記憶體空間是否能承受該
10億天記錄
ø堆實現
用堆的方式儲存源位址資訊,每個節點的結構為
typedef unsigned long u32;
struct node;偽碼
:u32 ip;
time time;//以
ip為key建立堆
ret = readline(&ip, &time);
while (ret != eof)
if (istoday(time)) (p->visittoday)++;
is (isthisweek(time)) (p->visitthisweek)++;
ret = readline(&ip, &time);}//
以visittoday
為key
對堆進行重新排序,只要排出前
1000
個即可sortheaptopnwithvisittoday(1000);
printheaptopn(1000);//以
visitthisweek
為key
對堆進行重新排序,只要排出
1000
個即可sortheaptopnwithvisitthisweek(1000);
printheaptopn(1000);
l外部儲存的雜湊
我覺得要得出精確的結果,這個問題要分解成兩個問題
1.統計
ip訪問量日訪問量
2.進行排序
問題1,
確實無法在記憶體裡完成統計,需要借助外部儲存,我暫時能想到的高效的文字檔案結構式是根據
ip進行雜湊,例如
127.0.0.1,
將雜湊到檔案
/127/0/0/ip.dat
這個檔案中,
ip.dat
中將儲存
255個記錄,記錄,均按照
24位二進位制存放,
24位中頭
8位為乙個整形用於存放
ip最後一段,後
16為為長整形用於存放訪問次數,
ip.dat
在建立的時候將直接填滿
24*255
的長度,根據
ip的最後一段進行檔案中的位置定位,這樣就能夠知道這條記錄在
ip.dat
中的文位置,便於改寫(例如
127.0.0.1,1
就在這個檔案中的首位,
127.0.0.129
就在129*24
的位置上)。在統計的過程中,要注意一次要統計一定的記錄數量後,在寫入磁碟,這樣可以降低磁碟讀寫次數,例如,做乙個位圖,
key為
ip,value
為次數,遍歷日誌檔案,當這個點陣圖中的
key超過了
10萬條則寫入磁碟。問題2
,實際上這個問題是如何收集
1000
條值最高的記錄,而不應該是
對所有的記錄進行全部的排序,這樣的話,可以通過乙個大根堆,來進行過濾,每當堆內的節點達到
1001
的時候則將最小的
remove
掉,這樣就將大資料量的排序的問題轉化為小資料量排序,在遍歷了一遍
step1
中的統計結果後,就能夠得出準確的結果了
l演算法設計與分析方面
分成
2個步驟,第乙個步驟是分類統計
如果記憶體足夠,就使用陣列,2的
32次方大小的
uint
陣列,也就是
16gb
。如果記憶體不夠,又不會出現太壞的情況,就用平衡樹。(由於記憶體分配的原因,但如果出現最壞或者很壞的情況,比如
10億個
ip中有
1億個以上不同的
ip,平衡樹實際所需要的記憶體反而比陣列要大)
第二個步驟,就是在第乙個步驟的基礎上進行排序,找出最多的
1000個ip
了最容易想到的就是快速排序,時間複雜度是
o(n*log2n)
。堆排序的效率並不比快速排序高。
但這裡的題目並不是要求我們對所有的
ip進行排序,只是求出前
1000個ip
。所以,對於第二步,有另外一種思路,可以更高效的獲得結果。
這裡做乙個假設,最後
10億個
ip中有
1億個不同的
ip。需要在1億個
ip中找到
1000個ip
。對於快速排序來說複雜度就是
: n*log2n
(n=1
億)。大概等於
26億。
這裡不直接使用快速排序,而是分為三個步驟。
步驟2.1:
ip1,ip2......ip100000000.
現在ip1
與ip2
比較,ip3
與ip4
比較,ip99999999
與ip100000000
比較,得到較大的ip。
假設是ip2,ip4,ip5,ip8.......ip99999999.繼續2
個2個的比較,得到較大的ip。
假設是ip2,ip8......ip99999999
。這樣經過
m次比較(這裡
m=13
),最後得到了大概
1萬個左右的ip。
步驟2.1
複雜度是固定的,並且小於n(
n=1億)
步驟2.2:
這個時候對這
1萬個左右的
ip進行快速排序,複雜度是
x*log2x
(x=1
萬),找出前
1000個ip
。步驟2.3:
那麼剩下
1000個ip
,對於那大概
9000
個左右的
ip,以及被這
9000個ip
淘汰掉的
ip,都可以扔掉了。
我們只需要考慮
1000個ip
以及和被他們淘汰的
ip,也就是
1000*2的m
次方(這裡
m=13
),總共大概是
800萬個ip。
這個時候對
800萬個
ip進行快速排序,複雜度是
y*log2y
(y=800
萬)最終的時間複雜度是步驟
2.1,2.2,2.3
的總和,這裡得到的結果大概是:
1億(步驟1)
+ 13
萬(步驟2)
+ 1億
8千萬(步驟
3),大概是
3億不到。
補充:對於步驟
2,我這裡
m=13
只是隨意給出的乙個方案,對於不同的情況,
m都不一樣,可以通過複雜的計算得到
m的最優值。另外,對於步驟
2.3,實際上也可以遞迴分解為和步驟
2一樣的
3個步驟。
資料量這麼大
,無論是用什麼工具去處理都是不太好處理的
. 我想法
: 1)
它是按時間來進行統計的.所以
,第一步
,我覺得需要把這個十幾億或者是過百億行的檔案拆分了多個檔案
.可以按每小時或者每半小時為乙個檔案
2) 當拆分了多個檔案後
,每個檔案中的
ip進行統計
,並且記錄在永續性介質中
3) 重永續性介質中
,再通過
hash
等方式來進行排序
總結:
到了10
億這個層面上
,常用演算法都是變得相當無力
.我思想是現實有限硬體條件下
,可以對大資料量處理進行拆分,統計
,再重組來處理
.若假象在無限制硬體條件下
,雜湊的方式應該是最快吧
.
金山筆試題(武漢)
4個題 第一題交換兩個變數的值 不能使用臨時變數 第二題,逆序乙個單鏈表 第三題,c 的構造和析構。第四題,三選一 1,字符集的問題 2,com元件的問題 3,跨平台程式設計的問題。解答 第一題 一下還是沒想到,跟乙個同學討論了一下,後面都沒想到。就網上搜了一下。有兩種方法i,不過有一種不是很保險的...
2012 9 26 金山WPS筆試題
今晚的筆試題目不難,所考演算法也不是很難,關鍵在仔細審題和平常的積累 1.有770個節點的完全二叉樹,問葉子節點有多少?重點是葉子節點,不是最下一層的節點數目,陷阱呀 可以計算得出該完全二叉樹的最下面一層的節點數目是259,上一層的節點數目為256,所以,可以得出上一層的葉子節點數目有126,所以結...
一道2005金山筆試題
問題描述 2005年11月金山筆試題。編碼完成下面的處理函式。函式將字串中的字元 移到串的前部分,前面的非 字元後移,但不能改變非 字元的先後順序,函式返回串中字元 的數量。如原始串為 ab cd e 12,處理後為 abcde12,函式並返回值為5。要求使用盡量少的時間和輔助空間 include ...