C++一些关于 boost::unordered_map 和 boost::hash 的问题

C++ some questions on boost::unordered_map & boost::hash

本文关键字:boost map hash 问题 unordered C++      更新时间:2023-10-16

我最近才开始研究boost和它的容器,我在网上和stackoverflow上读了一些文章,说boost::unordered_map是大集合中执行最快的容器。我有这个类State,它在容器中必须是唯一的(不能重复)容器中有数百万甚至数十亿个状态。因此,我一直在尝试优化它的小尺寸和尽可能少的计算。我以前使用boost::ptr_vector,但正如我在stackoverflow上读到的,只要vector中没有那么多对象,它就是好的。在我的例子中,状态描述了来自机器人的感觉运动信息,所以可能有大量的状态,因此快速查找是最重要的。看了unordered_map的boost文档后,我意识到有两件事可以加快速度:使用hash_function,并使用相等运算符根据各州的hash_function来比较它们。因此,我实现了一个私有hash()函数,它接受State信息,并使用boost::hash_combine创建一个std::size_t哈希值。操作符==基本上比较状态的哈希值。所以:

  • 的std::size_t足以覆盖数十亿个可能的hash_function组合呢?为了避免重复状态,我打算使用hash_values。

  • 创建state_map时,我应该使用State*还是hash作为键价值吗?即:boost::unordered_map<State*,std::size_t> state_map;boost::unordered_map<std::size_t,State*> state_map;

  • 是boost::unordered_map::iterator =的查找时间State_map.find()比boost::ptr_vector和比较每个迭代器的键值

  • 最后,关于如何优化这种无序地图的任何提示或技巧

编辑:我已经看到了相当多的答案,一个是不使用boost,但c++ 0X,另一个不使用unordered_set,但说实话,我仍然想看看如何boost::unordered_set与哈希函数一起使用。我已经按照boost的文档和实现,但我仍然不知道如何使用boost的哈希函数与有序集。

这有点混乱。

  • 你说的不是"你可以做些什么来加快速度";相反,它们是您的类型的强制性要求,以便有资格作为无序映射的元素类型,也适用于无序集合(这是您可能希望的)。

  • 您需要提供一个相等操作符来比较对象,而不是哈希值。相等的全部意义在于区分具有相同哈希值的元素。

  • size_t为无符号整型,x86为32位,x64为64位。由于您需要"数十亿个元素",这意味着许多gb的数据,我假设您有一台可靠的x64机器。

  • 关键是你的哈希函数是好的,即很少有冲突。

  • 你想要一个集合,而不是一个地图。将对象直接放在set: std::unordered_set<State>中。如果要将映射到,即将状态映射到其他东西,则使用映射。哦,如果可以的话,使用c++ 0x,而不是boost。

  • 使用hash_combine是好的


婴儿的例子:

struct State
{
  inline bool operator==(const State &) const;
  /* Stuff */
};
namespace std
{
  template <> struct hash<State>
  {
    inline std::size_t operator()(const State & s) const
    {
      /* your hash algorithm here */
    }
  };
}
std::size_t Foo(const State & s) { /* some code */ }
int main()
{
  std::unordered_set<State> states; // no extra data needed
  std::unordered_set<State, Foo> states; // another hash function
}

unordered_map是一个散列表。你不存储哈希;它是作为存储和查找方法在内部完成的。

考虑到您的需求,unordered_set可能更合适,因为您的对象是唯一要存储的项。

您可能有点困惑——相等操作符和哈希函数并不是真正的性能项,而是容器正常工作所需的重要对象。一个好的哈希函数会将节点均匀地分布到桶中,并且相等运算符将用于消除基于哈希函数的匹配的任何歧义。

std::size_t可以用于哈希函数。记住,没有一个哈希是完美的;将会有冲突,这些冲突项将被存储在该桶位置的链表中。

因此,.find()在最优情况下将是O(1),在平均情况下非常接近O(1)(在最坏情况下是O(N),但一个像样的哈希函数将避免这种情况)

你没有提到你的平台或架构;对于数十亿个条目,您仍然可能需要担心内存不足的情况,这取决于这些情况和State对象的大小。

忘记散列;没有什么(至少从你的问题中)表明你有一个有意义的钥匙;

让我们退后一步,重新表述你的实际性能目标:

  • 您想要快速验证任何状态对象不存在重复

注释如果我需要添加其他

根据上述目标和您的评论,我建议您实际使用ordered_set而不是unordered_map。是的,有序搜索使用二进制搜索O(log (n)),而无序搜索使用查找O(1)。

然而,不同之处在于,使用这种方法,您需要ordered_set ONLY来检查当您要创建一个新的时,即在state 创建时间时,是否已经存在类似的状态

所有其他查找中,实际上不需要查看ordered_set!因为你已经有钥匙了;状态*,键可以通过解引用操作符访问该值:*key

因此,使用这种方法,您只使用ordered_set作为索引,仅在创建时验证状态。在所有其他情况下,您可以使用指针-值键的解引用操作符访问State。

如果以上这些还不足以说服你,那么这里是使用哈希来快速确定等式的想法的最后一颗钉子;哈希函数发生碰撞的概率很小,但随着状态数的增加,这种概率将变得完全确定。所以根据你的容错性,你将处理状态冲突(从你的问题和你期望处理的状态数量来看,你似乎会处理很多)

要做到这一点,你显然需要比较谓词来测试状态的所有内部属性(陀螺仪,推进器,加速度计,质子射线等)