【问题标题】:unordered_map to find indices of an arrayunordered_map 查找数组的索引
【发布时间】: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。如果您只是添加元素,也许您可​​以进行大量预订,然后将元素一个接一个地放置

标签: c++ performance set 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!,他的示例有点小,但您可以大致了解。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多