题目:
1、海量日志数据,提取出某日访问百度次数最多的那个IP。
假设有一个大文件,里面以字符形式存储了IP与IP访问次数,这两数据按空格隔开,然后一行对应一个IP。
解决思路
算法思想:分而治之+Hash
1.IP地址最多有2^32=4G种取值情况,所以不能完全加载到内存中处理;
2.可以考虑采用“分而治之”的思想,按照IP地址的Hash(IP)%1024值,把海量IP日志分别存储到1024个小文件中。这样,每个小文件最多包含4MB个IP地址;
3.对于每一个小文件,可以构建一个IP为key,出现次数为value的Hash map,同时记录当前出现次数最多的那个IP地址;
4.可以得到1024个小文件中的出现次数最多的IP,再依据常规的排序算法得到总体上出现次数最多的IP;
解决过程中的问题:
(1)我的是FAT16文件系统,一个根目录下文件数量有限制,只能存放512个文件,我在批量创建的时候因为限制只有509个,所以我就按照509开始分文件
(2)
批量打开文件的函数
应当注意的是在写文件描述符关闭后才可以打开读的
void openFileOut(ofstream *out)
{
for (int i = 0; i < 509; ++i)
{
char path[100] = "D:\\VS2015\\代码\\C++file\\C++file\\文件\\";
char name[10] = { 0 };
_itoa_s(i, name, 10);
strcat_s(name, ".txt");
strcat_s(path, name);
out[i].open(path);
}
}
void openFileIn(ifstream *in)
{
for (int i = 0; i < 509; ++i)
{
char path[100] = "D:\\VS2015\\代码\\C++file\\C++file\\文件\\";
char name[10] = { 0 };
_itoa_s(i, name, 10);
strcat_s(name, ".txt");
strcat_s(path, name);
in[i].open(path);
}
}
对应的测试函数,起码创建和读取都没有问题
int main()
{
ofstream out[509];
ifstream in[509];
openFileOut(out);
//测试是否能够有效写入
for (int i = 0; i < 509; ++i)
{
char name[4] = { 0 };
_itoa_s(i, name, 10);
out[i].write(name,strlen(name));
}
for (int i = 0; i < 509; ++i)
{
out[i].close();
}
openFileIn(in);
//测试是否能够有效读取
for (int i = 0; i < 509; ++i)
{
long size;
char* buffer;
in[i].seekg(0, ios::end);
int l = in[i].tellg();
in[i].seekg(0, ios::beg);
int m = in[i].tellg();
size = l-m;
// cout << "size=" << size<<endl;
buffer = new char[size+1];
buffer[size] = '\0';
in[i].read(buffer, size);
in[i].close();
cout << buffer << endl;
delete[] buffer;
}
for (int i = 0; i < 509; ++i)
{
in[i].close();
}
return 0;
}
自己给的求哈希地址的函数(要让他均衡分布,我也不知道自己取法算不算优异)
int getHash(char* str)
{
int result = 0;
const char *d = ".";
char *p=NULL;
char* pNext = NULL;
p = strtok_s(str, d, &pNext);
while (p)
{
result = atoi(p)*(rand()%255)+result;//这个就是让计算随机化
p=strtok_s(NULL, d,&pNext);
}
return result%1024;//获取哈希的值然后写到应有的文件中去
}
接下来就是读取一下大的文件,把每一行的数据按照哈希分布分布到它应当存储的那一号文件中去,分布完成,关闭所有写,开始按照内存取得方法,取出509个文件中的分别的最大值,然后再进行一次比较就好了