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