具有整数键的C ++高效且紧凑的映射

时间:2016-07-30 16:33:06

标签: c++ optimization data-structures

我有200套约50,000个独特的整数,范围在0到500,000之间,我需要映射到另一个小值(一对整数,值不相关,因此没有按需计算)。

我尝试使用std :: unordered_maps,这使用了大约50MB(在VS2015堆诊断工具中测量),虽然性能很好但是我想降低内存使用率(打算成为一个小型500MB的后台服务)云服务器)。

实际上,我的初始版本是200个单独的std::unordered_map<int, std::pair<int, int>>

一个选项似乎是一个排序数组并使用二进制搜索,但还有其他什么吗?

3 个答案:

答案 0 :(得分:1)

我认为有序矢量应该有效,如果您在排序后不能更改矢量。它真的节省空间,即没有指针开销。

如果您需要更好的性能,请不要介意某些第三方库。您可以尝试sparse_hash_map,它实现哈希映射,空间开销很小。

答案 1 :(得分:1)

我想最有效的内存将是std::vector<std::pair<int, std::set<Something>>>,就像你已经建议的那样。

在这种情况下,您只会因以下原因而产生内存开销:

  • 来自std :: vector的固定开销(非常有限)
  • 有时在“成长”期间内存使用量会增加。因为旧数据和新数据必须在那一刻活着
  • std :: vector
  • 中未使用的空格

你有点表示在构建之后你不再需要扩展向量,所以你可以reserveshrink_to_fit去除未使用的空间。 (注意,reserve还可以修复增长期间内存使用量的峰值)

如果您的用途更密集,可以考虑将存储空间更改为std::vector<std::set<Something>>std::vector<std::unique_ptr<std::set<Something>>>。在这种结构中,索引是隐式的,尽管只有每个索引都有一个值时才会显示内存增益。

使用向量的缺点是您必须编写一些自定义代码。在这种情况下,std::unordered_mapstd::map如果你不想在处理器缓存(L1 ...)上考虑更多标准实现的更多缓存未命中,那就太糟糕了,可以查看Googles sparsehashGoogles cpp-btreeFacebooks AtomicHashMap from Folly,但我没有任何使用经验。

最后,人们可能想知道为什么你在内存中都有这些数据,但是如果你需要最佳性能,我也没有办法预防这种情况。

答案 2 :(得分:1)

为了有效存储,根据精确的值范围,您可能希望使用位操作将键/值对存储在单个值中:例如,如果值非常小,您甚至可以使用24位键和8位用于值,从而产生单个32位条目。我相信现在大多数编译器使用32或64位对齐,因此存储例如32位密钥和16位值可能仍然需要每个条目64位。如果瓶颈是内存总线和缓存未命中而使用简单压缩也可能对性能有利,而不是CPU本身。

然后,这取决于您想要执行的操作类型。存储密钥的最简单方法是排序的结构数组或我上面提出的组合ley / value条目。这是快速且非常节省空间的,但需要O(log n)查找。

如果你想要更加花哨,你可以使用perfect hashing,我们的想法是找到一个哈希函数,为每个键产生唯一的哈希值。这允许hashmap是一个简单的数组,它只需要比我上面提到的排序数组略大。找到一个好的哈希函数应该相对较快,你可以通过使数组更大一些并允许数组中的一些未使用的字段来使它更容易。 Here是完美哈希的实现,但我自己没有使用它。

在这两种情况下,内存消耗将是:(对的数量)*(每个条目的位数)位,以及在使用第二种方法时存储散列函数。

**编辑**

@FireLancer发表评论后更新。另外,添加了一些关于压缩数组性能的文字。