Visual c++ CMap初始化哈希表大小
在我的程序中,Visual c++ CMap初始化哈希表大小,visual-c++,mfc,hashtable,Visual C++,Mfc,Hashtable,在我的程序中,CMap的大小乘以1.2 IIRC 6230,这比我用来InitHashTable(6203)的大小要好 我放入另一个InitHashTable值,它是一个素数:9973 那么这是正确的吗?或者我应该选择一个更接近6203的素数。或者我可以选择一个更大的素数?std::map使用红黑树,CMap实现为哈希表。这是两个完全不同的容器。根据MSDN的最佳性能,哈希表大小应该是一个素数。为了尽量减少碰撞,大小应该比最大的预期数据集大约大20%。这是使用VS2015的CMap的测试结果。它
CMap
的大小乘以1.2 IIRC 6230,这比我用来InitHashTable
(6203)的大小要好
我放入另一个InitHashTable
值,它是一个素数:9973
那么这是正确的吗?或者我应该选择一个更接近6203的素数。或者我可以选择一个更大的素数?
std::map
使用红黑树,CMap
实现为哈希表。这是两个完全不同的容器。根据MSDN的最佳性能,哈希表大小应该是一个素数。为了尽量减少碰撞,大小应该比最大的预期数据集大约大20%。这是使用VS2015的CMap
的测试结果。它建议使用素数并没有太大的区别,初始化值是比预期值多20%还是少20%也无关紧要
有或没有素数或初始化都没有错误。我假设CMap
文档中提到的“冲突”与性能有关
对于较大的数据集,可以只使用预期的数据大小。例如,如果预期大小为6000,则只需使用map.InitHashTable(6000)
。默认值为17,较低的值将降低性能
还有std::map的测试结果,它不需要初始化,速度非常快
void test()
{
CString msg;
//build test vector
int size = 100000;
std::vector<CString> vs;
for (int i = 0; i < size; i++)
{
CString s;
s.Format(L"str%d", i);
vs.push_back(s);
}
{//using prime number, 20% larger than expected size
int t = GetTickCount();
int init_size = 120011;
CMap<LPCTSTR, LPCTSTR, int, int> map;
map.InitHashTable(init_size);
for (int i = 0; i < size; i++)
map[vs[i]] = i;
msg.AppendFormat(L"CMap Initialized: %d, time:%d\n", init_size, GetTickCount() - t);
}
{//using non-prime number and 20% less than expected size
int t = GetTickCount();
int init_size = 80000;
CMap<LPCTSTR, LPCTSTR, int, int> map;
map.InitHashTable(init_size);
for (int i = 0; i < size; i++)
map[vs[i]] = i;
msg.AppendFormat(L"CMap Initialized: %d, time:%d\n", init_size, GetTickCount() - t);
}
{//using non-prime number and default initialization (m_nHashTableSize=17)
int t = GetTickCount();
CMap<LPCTSTR, LPCTSTR, int, int> map;
for (int i = 0; i < size; i++)
map[vs[i]] = i;
msg.AppendFormat(L"CMap Initialized: %d, time:%d\n", 17, GetTickCount() - t);
}
{//std::map test
int t = GetTickCount();
std::map<CString, int> mp;
for (int i = 0; i < size; i++)
mp[vs[i]] = i;
msg.AppendFormat(L"std::map time:%d\n", GetTickCount() - t);
}
//error test:
int init_size = 1000; //only a fraction of expected size!
CMap<LPCTSTR, LPCTSTR, int, int> map;
map.InitHashTable(init_size);
for (int i = 0; i < size; i++)
map[vs[i]] = i;
for (int i = 0; i < size; i++)
{
if (map[vs[i]] != i)
{
AfxMessageBox(L"errorTest - fail");
return;
}
}
msg.AppendFormat(L"no error");
AfxMessageBox(msg);
}
结果只是一个粗略估计如果可能,使用
std::map
CMap
对素数的说明很奇怪。我真的很想听从你的建议,但我使用的是一个旧代码,修改它不是我的职责:\n仔细想想,CMap
如果你知道初始大小,似乎有一些优势std::map
无法设置初始大小,因此速度较慢。我运行了一些测试,它表明是否有素数并不重要,init大小是否大20%也不重要。只要init大小大致在它应该的位置,它就会很快。Barmak,如果我使用一个大的哈希表(比假设的大小大100%),我会有冲突之类的问题吗?(请原谅我的愚蠢问题)阿米诺斯,文件很模糊。“冲突”可能指的是性能问题。如果这是一个错误,那么您希望消除冲突,而不是最小化冲突。我认为CMap
试图分配一个新项目,它可能会看到与现有项目的冲突,因此它必须分配一个新项目,这会浪费几纳秒的时间。也许这就是文档所警告的。我在另一个答案中添加了一些测试。我也做了一个基准测试,哈希映射大小即使与预期大小相比太小,也没有数据丢失。但是,性能会显著降低(例如,当访问数据时,std::map为0.5秒,而CMap为22秒,哈希值非常小-如果哈希表的大小正确,CMap优于std::map,例如0.4秒与0.5秒)
CMap Initialized: 120011, time:31
CMap Initialized: 80000, time:47
CMap Initialized: 17, time:5110
std::map time:78
no error