提取出某日访问百度次数最多的那个IP

提取出某日访问百度次数最多的那个IP

问题描述:海量日志数据,提取出某日访问百度次数最多的那个IP。

方法: 计数法

    假设一天之内某个IP访问百度的次数不超过40亿次,则访问次数可以用unsigned表示.用数组统计出每个IP地址出现的次数,  即可得到访问次数最大的IP地址.

    IP地址是32位的二进制数,所以共有N=2^32=4G个不同的IP地址, 创建一个unsigned count[N];的数组,即可统计出每个IP的访问次数,而sizeof(count) == 4G*4=16G, 远远超过了32位计算机所支持的内存大小,因此不能直接创建这个数组.下面采用划分法解决这个问题.

    假设允许使用的内存是512M,  512M/4=128M 即512M内存可以统计128M个不同的IP地址的访问次数.而N/128M =4G/128M = 32 ,所以只要把IP地址划分成32个不同的区间,分别统计出每个区间中访问次数最大的IP, 然后就可以计算出所有IP地址中访问次数最大的IP了.

    因为2^5=32, 所以可以把IP地址的最高5位作为区间编号, 剩下的27为作为区间内的值,建立32个临时文件,代表32个区间,把相同区间的IP地址保存到同一的临时文件中.

例如:

ip1=0x1f4e2342

ip1的高5位是id1  =  ip1 >>27 = 0x11 = 3

ip1的其余27位是value1  =  ip1 &0x07ffffff = 0x074e2342

所以把 value1 保存在tmp3文件中.

由id1和value1可以还原成ip1, 即 ip1 =(id1<<27)|value1

    按照上面的方法可以得到32个临时文件,每个临时文件中的IP地址的取值范围属于[0-128M),因此可以统计出每个IP地址的访问次数.从而找到访问次数最大的IP地址。

测试代码如下:

#include<fstream>
#include<iostream>
#include<ctime>

using namespace std;
#define N 32

#define ID(x) (x>>27)
#define VALUE(x) (x&0x07ffffff)
#define MAKE_IP(x,y) ((x<<27)|y)

#define MEM_SIZE 128*1024*1024

char* data_path="D:/test/ip.dat";
//随机产生n个随机IP地址
void make_data(const int& n)
{
ofstream out(data_path,ios::out|ios::binary);
srand((unsigned)(time(NULL)));
if(out)
{
 for(int i=0;i<n;i++)
 {
   unsigned val=unsigned(rand());
val=(val<<24)|val;
out.write((char*)&val,sizeof(unsigned));
 }
}
}

int main()
{
  make_data(100000000);
  fstream arr[N];
  for(int t=0;t<N;t++)
  {
    char tmp_path[128];
sprintf(tmp_path,"D:/test/tmp%d.dat",t);
arr[t].open(tmp_path,ios::trunc|ios::in|ios::out|ios::binary);
if(!arr[t])
{
 cout<<"open file"<<t<<"error"<<endl;
}
  }
  ifstream infile(data_path,ios::in|ios::binary);
  unsigned data;
  while(infile.read((char*)(&data),sizeof(data)))
  {
    unsigned val=VALUE(data);
int key=ID(data);
arr[ID(data)].write((char*)(&val),sizeof(val));
  }
  for(unsigned k=0;k<N;k++)
  {
    arr[k].seekg(0);
  }
  unsigned max_ip=0;
  unsigned max_times=0;
  unsigned *count=new unsigned[MEM_SIZE];
  for(unsigned i=0;i<N;i++)
  {
    memset(count,0,sizeof(unsigned)*MEM_SIZE);
unsigned data;
while(arr[i].read((char*)(&data),sizeof(unsigned)))
{
 ++count[data];
}
    for(unsigned j=0;j<MEM_SIZE;++j)
{
 if(max_times<count[j])
 {
   max_times=count[j];
max_ip=MAKE_IP(i,j);
 }
}
  }
  delete[] count;
  unsigned char* result=(unsigned char*)(&max_ip);
  printf("出现次数最多的IP位:%d.%d.%d.%d,共出现%d次",result[0],result[1],result[2],result[3],max_times);
  return 0;
}

参考来源:《程序员编程艺术》——by July
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值