最快的C ++地图?

时间:2010-07-07 19:24:52

标签: c++ performance data-structures map

纠正我我错了,但是std :: map是一个有序的映射,因此每次插入一个值时,map都会使用算法在内部对其项进行排序,这需要一些时间。

我的应用程序以恒定的间隔获取有关某些项目的信息。

此应用程序会保留一个定义如下的地图:

::std::map<DWORD, myItem*>

首先,所有项目都被视为应用的“新”项。正在分配“Item”对象并将其添加到此映射,并将其id和指向它的指针相关联。

当它不是“新”项目(只是对象的更新)时,我的应用程序应该使用给定的ID在地图上找到对象并进行更新。

大多数时候我都会得到更新。

我的问题是:
是否有更快的地图实现或我应该继续使用这个? 我最好使用unordered_map吗?

3 个答案:

答案 0 :(得分:41)

  

我最好使用unordered_map吗?

可能。

std:map在O(log n)处提供一致的性能,因为它需要实现为平衡树。但是std:unordered_map将被实现为哈希表,它可能会给你O(1)性能(良好的哈希函数和跨哈希桶的密钥分配),但它可能是O(n)(一个哈希桶中的所有东西)转到列表)。人们通常会期待这些极端之间的某些东西。

因此,您可以始终保持合理的性能(O(log n)),或需要确保所有内容都能通过哈希获得良好的性能。

与任何此类问题一样:您需要在采取一种方法之前进行衡量。除非您的数据集很大,否则您可能会发现没有显着差异。

答案 1 :(得分:9)

重要警告:除非您已经测量过(并且您的问题表明您没有),否则地图性能会严重影响您的应用程序性能(大部分时间用于搜索和更新地图)不要费心去加快速度。 坚持std::map(或std::unordered_map或任何可用的hash_map实施)。 将您的应用程序加速1%可能不值得付出努力。 让它免于bug。

回应理查德的回答:衡量使用您的真实班级和真实数据进行不同地图实施的表现。

一些补充说明:

  • 了解预期成本(哈希映射通常使其更低)之间的差异,最差情况成本(平衡二叉树的O(logn),但如果插入触发哈希数组的重新分配,则哈希映射要高得多)并且摊销成本(总成本除以运营或要素数量;取决于新元素和现有元素的比例)。你需要找出哪个更适合你的情况。例如,如果您需要遵守非常低的延迟限制,重新分配哈希映射可能会太多。

  • 找出真正的瓶颈所在。与例如相比,在地图中搜索的成本可能是微不足道的。 IO费用。

  • 尝试更专业的地图实施。例如,如果您对地图的密钥有更多了解,可以获得很多。通用地图实现的作者没有这样的知识。

在您的示例中(强烈聚类的32位无符号整数键,例如按顺序分配),您可以使用基于基数的方法。 非常简单示例(威胁它作为插图,尚未准备好使用食谱):

Item *sentinel[65536];  // sentinel page, initialized to NULLs.
Item (*pages[65536])[65536];  // list of pages,
                              // initialized so every element points to sentinel

然后搜索就像:

Item *value = pages[index >> 16][index & 0xFFFF];

当您需要设置新值时:

if (pages[index >> 16] == sentinel) {
  pages[index >> 16] = allocate_new_null_filled_page();
}
pages[index >> 16][index & 0xFFFF] = value;
  • 调整您的地图实施。

    • E.g。每个hash_map都希望事先知道元素的大致数量。它有助于避免不必要的重新分配哈希表和(可能)重新散列所有键。

    • 通过上面的专业示例,您肯定会尝试不同的页面大小或三级版本。

    • 常见优化是提供专门的内存分配器,以避免小对象的多次分配。

答案 2 :(得分:0)

每当插入或删除项目时,内存分配/取消分配都会花费​​很多。取而代之的是,您可以使用这样的分配器:https://github.com/moya-lang/Allocator,其速度达到std :: map的两倍,正如作者所说的那样,但是我发现它甚至更快,尤其是对于其他STL容器。