http://topic.csdn.net/u/20081224/16/23041dbb-b0b9-46c5-9ff7-3a4dede2a6e3.html
1、這是今年百度的一道筆試題。給你1億個ip地址和每個ip訪問的時間(00:00:00= <時間 <=23:59:59,並且已經按照時間排好序了),然後給定一段時間X,定義在X內如果某IP的訪問次數超過Y次,則判定該IP爲攻擊IP。要求輸出所有攻擊IP。只有一組測試用例。第一行輸入IP記錄數(即10萬),時間X(10= <X <=120秒),次數Y(2= <Y <=100)。輸出按訪問的時間順序輸出,IP重複不再輸出。
輸入示例:(爲了方便,只給出8個,意思意思)
8 10 2
10.254.82.126 00:00:39
10.85.124.135 00:00:40
10.254.82.126 00:00:44
10.254.82.126 00:00:44
10.1.82.125 00:00:45
10.85.124.135 00:00:48
10.254.82.126 00:00:48
10.254.82.126 00:00:49
輸出示例:
10.254.82.126
10.85.124.135
2、偶覺得算法思想可以如下:
輸入隊列比如是
struct ipChain{
char ip[16];
char date[16];
}ipArray[100000];
在這個ipArray上 維持 2個動態標記: head 初始爲0 tail爲的index爲 ipArray[tail].date - ipArray[head].date <= X 並且 ipArray[tail+1].date - ipArray[head].date > X。
將 tail - head + 1個元素 進行散列,加下每個ip的 count 大於Y的直接 可以輸出
以後 tail++, 查看先加入的元素是否 使 ipArray[tail].date - ipArray[head].date > x, 大於 則 head++,且 散列表中其count--,一旦爲0,刪除之。然後 將新加入的ipArray[tail] 加入散列表 查看是否 count > Y。
這樣的話 算法 應該比 O(n)差不了多少。
3、能把哈希函數告訴嗎?
就是把IP地址散列到10萬的數以內,我是這樣做的
例如:192.168.0.1
hash = ((192 × 192) % 100000 + (168 × 168)% 100000 + (0 × 0)% 100000 + (1 * 1) % 100000) % 100000
有衝突就向後找空位
但是效率不高
求一個效率高的哈希函數
4、你自己可以根據 X的大小來選取一個平均的 hash 表長度哈
比如 x = 60(秒)(平均值)
1/60/24 * 1億 = 7萬左右
長度選取 10萬應該挺合理的。
hash那就更簡單了 IP 0.0.0.0 正好對應 4* 8(bits) = 32位(1個int)
寫個函數 int ip_to_int(const char *ip);
將返回的數字 ret % 100000作爲哈希數組索引
5、引用 8 樓 huangzhtao 的回覆:
能把哈希函數告訴嗎?
就是把IP地址散列到10萬的數以內,我是這樣做的
例如:192.168.0.1
hash = ((192 × 192) % 100000 + (168 × 168)% 100000 + (0 × 0)% 100000 + (1 * 1) % 100000) % 100000
有衝突就向後找空位
但是效率不高
求一個效率高的哈希函數
還有關於衝突 我覺得你的解決方法 不是很理想,找空位的方法萬一制定x時間內 ip地址超過10萬個呢?所以hash表的 element好好設計下
偶覺得可以
struct hash_element{
const char *ip;
int count;
struct hash_element *next;
};
ip就放 當前被hash的ip地址字符串的地址,count個數 next指向下一個衝突的地址。
這樣 hash_elemnt[100000];的一個hash表應該能搞定
6、引用 13 樓 fisher_047 的回覆:
引用 9 樓 threeleafzerg007 的回覆:
你自己可以根據 X的大小來選取一個平均的 hash 表長度哈
比如 x = 60(秒)(平均值)
1/60/24 * 1億 = 7萬左右
長度選取 10萬應該挺合理的。
hash那就更簡單了 IP 0.0.0.0 正好對應 4* 8(bits) = 32位(1個int)
寫個函數 int ip_to_int(const char *ip);
將返回的數字 ret % 100000作爲哈希數組索引
我沒太理解9樓的將IP轉換成整數的方法,比如說192.0.0.1轉換後是1920…
const char *ip = "127.0.0.1";
int a1,a2,a3,a4,result = 0;
sscanf(ip,"%d.%d.%d.%d",&a1,&a2,&a3,&a4);
result |= a1 < < 24;
result |= a2 < < 16;
result |= a3 < < 8;
result |= a4;
7、由於條件上y <100,所以可以用byte數組散列
ip正好可以轉成uint32,這樣需要內存:
(2^32)b=4G Byte!!
如果就這麼回答完畢的話估計是沒分了.
可以考慮用鏈地址法來散列
只散列ip的前3段.
另外,多用位運算估計就可以了.
ip的哈希的問題解決了,然後就可以滾動掃描了