C++一些关于 boost::unordered_map 和 boost::hash 的问题
C++ some questions on boost::unordered_map & boost::hash
我最近才开始研究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。如果以上这些还不足以说服你,那么这里是使用哈希来快速确定等式的想法的最后一颗钉子;哈希函数发生碰撞的概率很小,但随着状态数的增加,这种概率将变得完全确定。所以根据你的容错性,你将处理状态冲突(从你的问题和你期望处理的状态数量来看,你似乎会处理很多)
要做到这一点,你显然需要比较谓词来测试状态的所有内部属性(陀螺仪,推进器,加速度计,质子射线等)
- 如何将 boost::hana::map 转换为 lambda
- 清除 std::map 的 boost::p ool_分配器不会在 VS2017 中返回整个池
- 如何在没有(constexpr)实例的情况下反省到boost::hana::map<...>?
- boost::hana::map 作为数据成员
- 无法让 Boost Spirit 语法使用 std::map 的已知键<>
- boost-python 当C++方法返回 std::map<string,X*>
- boost::spirit::qi::phrase_parser() into std::map error
- 将 boost odeint 与 std::map 和自定义向量空间代数一起使用时,没有可行的重载'='
- 在std :: map中插入boost :: unique_ptr
- 将std::map复制/插入到boost::bimap中
- 如何使用std::map和boost::phoenix
- 如何使用boost::mutex作为std::map中的映射类型
- 如何通过 C++ boost::序列化执行 std::map 的部分反序列化
- boost::interprocess::map insert 给出:对重载函数的不明确调用
- boost::interprocess::map - 如何使用basic_string作为类型更新值
- c ++如何使用boost xml解析器读取XML并存储在map中
- boost::lambda std::map
- boost::fusion::map 允许重复键
- 将boost::bind函数存储在std::map中
- 如何以"二维方式"使用 boost::variant 定义异构 std::map