unordered_map 查找数组的索引

Posted

技术标签:

【中文标题】unordered_map 查找数组的索引【英文标题】:unordered_map to find indices of an array 【发布时间】:2020-10-30 21:59:27 【问题描述】:

我想有效地找到一个集合的索引。我正在使用 unordered_map 并像这样制作逆映射

std::unordered_map <int, int> myHash (size); 
Int i = 0;
for (it = someSet.begin(); it != someSet.end(); it++)

    myHash.insert(*it , i++);
 

它有效,但效率不高。我这样做了,所以只要我需要索引,我就可以访问它们 O(1)。性能分析显示这部分成为我代码的热点。

VTune 告诉我 new 运营商是我的热点。我猜 unordered_map 内部正在发生一些事情。 在我看来,这个案子应该得到有效处理。我还没有找到好的方法。有更好的解决方案吗?一个正确的构造函数? 也许我应该将更多信息传递给构造函数。我查看了初始化列表,但它并不是我想要的。

更新:让我添加更多信息。套装没那么重要;我将集合保存到一个数组中(排序)。稍后我需要找到唯一值的索引。我可以在登录中做到这一点,但速度不够快。这就是我决定使用哈希的原因。集合的大小(子矩阵的列)在此之后不会改变。

它来自稀疏矩阵计算,我需要在更大的矩阵中找到子矩阵的索引。因此,查找的大小和模式取决于输入矩阵。它适用于较小的问题。我可以使用查找表,但是当我计划并行执行时,每个线程的查找表可能很昂贵。我在创建时具有哈希的确切大小。我认为通过将它发送给构造函数它会停止重新分配。我真的不明白为什么要重新分配这么多。

【问题讨论】:

Int?你的意思是int 你要转换多少个元素?你在做多少次查找?创建查找表的费用可能超过您获得的任何节省,因此它可能是错误的优化。有一些阈值,元素数量 > N 和查找数量 > M 产生正面结果,但低于该阈值实际上是净负面结果。 为什么要一个 set 元素的索引?即使你拥有它,访问元素(使用 std::distance() 也是 O(n)。 @ALX23z std::set 在调整大小时确实无效,它没有调整大小... 这个问题很可能是由于数组的大小。由于过大的碎片分配,使查找太大肯定会导致问题。考虑为您的项目解决算法问题。尝试以其他方式查找索引或使用pmr 分配unordered_map。如果您只是添加元素,也许您可​​以进行大量预订,然后将元素一个接一个地放置 【参考方案1】:

问题是,std::unordered_map,主要实现为向量列表,对缓存非常不友好,并且在使用小键/值时表现尤其差(例如 int,int 在您的情况下),更不用说需要大量(重新)分配。

作为替代方案,您可以尝试使用 linear probing 实现 open addressing 的第三方哈希映射(虽然很复杂,但底层结构只是一个向量,即对缓存更友好)。例如,谷歌的dense_hash_map 或这个:flat_hash_map。两者都可以用作unordered_map 的直接替代品,并且只需要另外指定一个int 值作为“空”键。

【讨论】:

std::unordered_map 在重新分配方面没有任何问题。也许查找表需要这些但不是基本元素。虽然它确实进行了大量分配,因此不建议使用大哈希。 我最终使用线性探测实现了我自己的哈希。效率更高。【参考方案2】:

std::unordered_map 经常被当作是

std::vector<std::list<std::par<int, int>>> 

这会导致每个节点的大量分配和解除分配,每个(解除)分配都使用会导致争用的锁。

您可以通过使用 emplace 代替 insert 来帮助它,或者您可以跳入 pmr 分配器的奇妙新世界。如果您对 pmr::unordered_map 的创建和销毁是单线程的,那么您应该能够从中获得很多额外的性能。请参阅 Jason Turners C++ Weekly - Ep 222 - 3.5x Faster Standard Containers With PMR!,他的示例有点小,但您可以大致了解。

【讨论】:

问题的描述是正确的,但我不太确定 PMR 是最好的建议。谷歌的哈希表被广泛使用,还有其他更快的选择 - probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable 是一个很好的阅读。

以上是关于unordered_map 查找数组的索引的主要内容,如果未能解决你的问题,请参考以下文章

unordered_map/set自定义哈希函数

在 C++ std::unordered_map 中预分配桶

从整数范围内搜索

3.索引与string进行映射实现高效查找

CDT 索引器找不到 std::unordered_map

使用stl :: map和stl :: unordered_map对包含大量重复元素的数组数据进行排序