只用2GB内在20亿个整数里中找到出现次数最多的数

题目
有一个包含20亿个全是32位整数的大文件,在其中找到出现次数最多的数,内存限制为2GB。
解答:
想要在很多整数中找到初夏次数最多的数,通常的做法是用哈希表对出现的每一个数据做词频统计,哈希表的key是某一个整数,value是这个词出现的次数。就本题来说,一共20亿个整数,用32位int型是完全足以表示的,32位int最大数据为2147483647,所以并不会溢出。因为一个哈希表需要的key需要4Bit空间,value也要4Bit空间,所以最大可能需要160亿Bit空间,即16GB空间,远远超过了2GB内存需求,因此需要分割,将大问题转化为小问题。

解决办法就是使用哈希函数将包含20亿个数的大文件使用哈希函数分成16个小文件,根据哈希函数的性质,同一个数据不可能被分割到不同的文件上,同时每个小文件中不同的数一定不会大于2亿个。当然了,哈希函数要选取合适,否者每个文件中数据的个数差异会很大,假设分割的小文件个数为N,那么将每个数对N求于,将余数为m的数存到m.txt文件里,经过试验,这种做法保证了每个文件里的数据量大致一致。

#include
#include
#include
using namespace std;
long long  NMAX = 2e7;
const int N = 16;//生成16个小文件
void create(string str)//生成NMAX个数据
{
	srand(unsigned(time(0)));
	ofstream fout(str);
	unsigned int num = 0;
	while (NMAX > 0)
	{
		num = rand() | (rand() << 16);//注意rand()生成的最大值只有0x7fff,因此要生成32位整数,把其左移16位
		fout << num << " ";
		--NMAX;
	}
	fout.close();
}
int hash(int key)//哈希函数
{
	return key%N;
}
void split(string name)
{
	char ch[100];
	ofstream f[N];
	ifstream fin(name);
	int num = 0;
	for (int i = 0; i < N; i++)//打开N个文件,供写入数据
	{
		_itoa_s(i, ch, 10);
		string str(ch);
		str = str + ".txt";
		f[i].open(str);
	}
	while (fin >> num)
	{
		int h = ::hash(num);
		f[h] << num << " ";
	}
	fin.close();
	for (int i = 0; i < N; i++)f[i].close();
}
void chose(int i, pair&p)//挑出第i个文件里的出现次数最多的数
{
	char ch[100];
	_itoa_s(i, ch, 10);
	string str(ch);
	str = str + ".txt";
	ifstream fin(str);//打开di个文件
	mapm;//key值记录数据,value记录出现的次数
	int key;
	while (fin >> key)m[key]++;
	map::iterator iter = m.begin();
	for (; iter != m.end(); iter++)
	{
		if (iter->second>p.second)//如果该数据出现的次数多,则替换
		{
			p.first = iter->first;
			p.second = iter->second;
		}
	}
	fin.close();
}
int main()
{
	clock_t start, end;
	pairp(0, 0);//记录出现次数最多的数,及其频次
	string name("test.txt");
	create(name);
	start = clock();
	split(name);
	for (int i = 0; i < N; i++)chose(i, p);
	end = clock();
	cout << p.first << " " << p.second << endl;
	cout << "time=" << (end - start)*1000.0 / CLOCKS_PER_SEC << "ms" << endl;
}


你可能感兴趣的:(2017校招编程题)