[英]C++ some questions on boost::unordered_map & boost::hash
我最近才开始研究 boost 及其容器,我阅读了一些关于 web 和 stackoverflow 的文章,其中 boost::unordered_map 是大型 collections 中性能最快的容器。 所以,我有这个 class State,它在容器中必须是唯一的(没有重复),容器中将有数百万甚至数十亿的状态。 因此,我一直在尝试将其优化为小尺寸和尽可能少的计算。 我之前使用过 boost::ptr_vector,但正如我在 stackoverflow 上所读到的,只要其中没有那么多对象,向量才是好的。 在我的例子中,State 描述了来自机器人的感觉运动信息,因此可能存在大量状态,因此快速查找是重中之重。 按照 unordered_map 的boost 文档,我意识到我可以做两件事来加快速度:使用 hash_function,并使用相等运算符根据它们的 hash_function 比较状态。 因此,我实现了一个私有 hash() function,它接收 State 信息并使用 boost::hash_combine,创建一个 std::size_t Z0800FC577294C34E0B258AD2839Z43 值。 operator== 基本上比较状态的 hash 值。 所以:
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 并比较每个迭代器的键值更快?
最后,任何关于如何优化这种无序 map 以实现速度和快速查找的提示或技巧将不胜感激。
编辑:我已经看到了很多答案,一个是不使用 boost 但 C++0X,另一个不使用 unordered_set,但老实说,我仍然想看看 boost::unordered_set 如何与 hash function 一起使用. 我遵循了boost的文档并实施了,但我仍然不知道如何使用有序集的boost hash function。
这有点糊涂了。
你所说的不是“你可以做些什么来加快速度”; 相反,它们是您的类型的强制性要求,才有资格作为无序 map 的元素类型,也适用于无序集(您可能更想要)。
您需要提供一个比较对象的相等运算符,而不是 hash 值。 相等的全部意义在于区分具有相同 hash 的元素。
size_t
是无符号整数类型,在 x86 上为 32 位,在 x64 上为 64 位。 由于您想要“数十亿个元素”,这意味着许多 GB 的数据,我假设您无论如何都有一台可靠的 x64 机器。
关键是您的 hash function 是好的,即很少发生碰撞。
你想要一套,而不是 map。 将对象直接放入集合中: std::unordered_set<State>
。 如果您要映射到某物,即状态到其他某物,请使用 map。 哦,如果可以的话,使用 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 是一个哈希表。 您不存储 hash; 它作为存储和查找方法在内部完成。
鉴于您的要求,unordered_set 可能更合适,因为您的 object 是唯一要存储的项目。
不过,您有点困惑——相等运算符和 hash function 并不是真正的性能项目,而是容器正常工作的重要对象所必需的。 A good hash function will distribute your nodes evenly across the buckets, and the equality operator will be used to remove any ambiguity about matches based on the hash function.
std::size_t 适用于 hash function。 请记住,没有 hash 是完美的; 会有碰撞,这些碰撞项存储在该桶 position 的链表中。
因此,.find() 在最佳情况下为 O(1),在平均情况下非常接近 O(1)(而在最坏情况下为 O(N),但一个不错的 hash function 将避免这种情况。)
您没有提及您的平台或架构; 在数十亿个条目中,您可能仍然需要担心内存不足的情况,具体取决于这些情况以及 State object 的大小。
忘记 hash; 没有任何东西(至少从你的问题来看)表明你有一个有意义的钥匙;
让我们退后一步,重新表述您的实际绩效目标:
如果我需要添加其他人,请发表评论。
从上述目标和您的评论来看,我建议您实际上使用ordered_set而不是unordered_map。 是的,有序搜索使用二进制搜索 O(log (n)),而无序使用查找 O(1)。
但是,不同之处在于,使用这种方法,您只需要ordered_set 来检查类似的 state在您即将创建一个新的时是否已经存在,即在 State创建时间。
在所有其他查找中,您实际上不需要查看ordered_set; 因为您已经拥有密钥 State*: 并且密钥可以通过魔术解引用运算符访问值: *key
因此,使用这种方法,您仅使用ordered_set 作为索引来仅在创建时间验证状态。 在所有其他情况下,您可以使用指针值键的取消引用运算符访问您的 State。
如果以上所有内容都不足以说服您,这里是使用 hash 快速确定相等性的想法的最后钉子; hash function 发生碰撞的概率很小,但是随着状态数量的增加,该概率将变得完全确定。 因此,根据您的容错能力,您将处理 state 碰撞(从您的问题和您期望处理的状态数量来看,您似乎会处理很多)
为此,您显然需要比较谓词来测试 state 的所有内部属性(陀螺仪、推进器、加速度计、质子射线等)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.