[英]convert regular `set` to boost's `unordered_set` in c++
I have a small program that is mostly using regular set
's but now that I'm getting a poor performance I decided to use unordered_set
from boost. 我有一个小程序,主要使用常规
set
,但是由于性能下降,我决定从boost使用unordered_set
。 I was optimistically thinking that a simple search and replace from set
to unordered_set
would do the trick with ofc the additional headers such as: 我乐观地认为,从
set
到unordered_set
的简单搜索和替换将通过使用额外的标题(例如:ofc)来解决问题
#include <boost/unordered_set.hpp>
using boost::unordered_set;
but now I have lots of compile errors. 但是现在我有很多编译错误。 I have looked into it and realized that even a simple nested
for
loop does not work. 我研究了它,意识到即使是简单的嵌套
for
循环也不起作用。 Here's an example: 这是一个例子:
unordered_set<unordered_set<int> > s;
unordered_set<int> temp;
temp.insert(5);
temp.insert(6);
temp.insert(7);
s.insert(temp);
s.insert(temp);
unordered_set<unordered_set<int> >::iterator it1;
unordered_set<int>::iterator it2;
for (it1 = s.begin(); it1 != s.end(); it1++) {
for (it2 = it1->begin(); it2 != it1->end(); it2++) {
cout << *it2 << endl;
}
}
which compiles fine when using set
but gives me: 使用
set
时可以很好地编译,但可以给我:
In file included from /usr/include/boost/functional/hash/hash.hpp:535:0,
from /usr/include/boost/functional/hash.hpp:6,
from /usr/include/boost/unordered/unordered_set.hpp:17,
from /usr/include/boost/unordered_set.hpp:16,
from foo.cpp:4:
/usr/include/boost/functional/hash/extensions.hpp: In member function ‘std::size_t boost::hash<T>::operator()(const T&) const [with T = boost::unordered_set<int>, std::size_t = long uns
igned int]’:
/usr/include/boost/unordered/detail/unique.hpp:363:1: instantiated from ‘boost::unordered_detail::hash_unique_table<T>::emplace_return boost::unordered_detail::hash_unique_table<T>::e
mplace_impl(const key_type&, const Arg0&) [with Arg0 = boost::unordered_set<int>, T = boost::unordered_detail::set<boost::hash<boost::unordered_set<int> >, std::equal_to<boost::unordere
d_set<int> >, std::allocator<boost::unordered_set<int> > >, boost::unordered_detail::hash_unique_table<T>::emplace_return = std::pair<boost::unordered_detail::hash_iterator_base<std::al
locator<boost::unordered_set<int> >, boost::unordered_detail::ungrouped>, bool>, typename T::iterator_base = boost::unordered_detail::hash_iterator_base<std::allocator<boost::unordered_
set<int> >, boost::unordered_detail::ungrouped>, boost::unordered_detail::hash_unique_table<T>::key_type = boost::unordered_set<int>]’
/usr/include/boost/unordered/detail/unique.hpp:398:36: instantiated from ‘boost::unordered_detail::hash_unique_table<T>::emplace_return boost::unordered_detail::hash_unique_table<T>::
emplace(const Arg0&) [with Arg0 = boost::unordered_set<int>, T = boost::unordered_detail::set<boost::hash<boost::unordered_set<int> >, std::equal_to<boost::unordered_set<int> >, std::al
locator<boost::unordered_set<int> > >, boost::unordered_detail::hash_unique_table<T>::emplace_return = std::pair<boost::unordered_detail::hash_iterator_base<std::allocator<boost::unorde
red_set<int> >, boost::unordered_detail::ungrouped>, bool>, typename T::iterator_base = boost::unordered_detail::hash_iterator_base<std::allocator<boost::unordered_set<int> >, boost::un
ordered_detail::ungrouped>]’
/usr/include/boost/unordered/unordered_set.hpp:339:40: instantiated from ‘std::pair<boost::unordered_detail::hash_const_iterator<typename boost::unordered_detail::rebind_wrap<A, T>::t
ype, boost::unordered_detail::ungrouped>, bool> boost::unordered_set<T, H, P, A>::insert(const value_type&) [with T = boost::unordered_set<int>, H = boost::hash<boost::unordered_set<int
> >, P = std::equal_to<boost::unordered_set<int> >, A = std::allocator<boost::unordered_set<int> >, typename boost::unordered_detail::rebind_wrap<A, T>::type = std::allocator<boost::uno
rdered_set<int> >, boost::unordered_set<T, H, P, A>::value_type = boost::unordered_set<int>]’
foo.cpp:17:18: instantiated from here
/usr/include/boost/functional/hash/extensions.hpp:176:34: error: no matching function for call to ‘hash_value(const boost::unordered_set<int>&)’
/usr/include/boost/functional/hash/extensions.hpp:176:34: note: candidates are:
/usr/include/boost/functional/hash/hash.hpp:144:24: note: std::size_t boost::hash_value(bool)
and some more when using unordered_set
. 使用
unordered_set
时还有更多。 What am I missing? 我想念什么?
You are missing a hash function for unordered_sets. 您缺少unordered_sets的哈希函数。 The bad news is, that you cannot easily construct one.
坏消息是,您不能轻易构建一个。 For example, the order in which you insert into your inner sets might cause a different ordering within the container, hence yielding a different hash if you use the naive way to construct it (as I did in the previous version of this answer :) )
例如,插入内部集合的顺序可能会导致容器内的顺序不同,因此如果您使用幼稚的方式构造它,则会产生不同的哈希值(就像我在此答案的上一版本中所做的那样:))
Either way, you need to pick a different container for your inner sets, and these sets need to be sorted. 无论哪种方式,您都需要为内部集选择一个不同的容器,并且需要对这些集进行排序。 I propose that you use
std::vector
or std::set
. 我建议您使用
std::vector
或std::set
。 Then you need a hash functor: you can use boost::hash_range
to easily construct one: 然后,您需要一个哈希函子:您可以使用
boost::hash_range
轻松构造一个:
template <class T>
struct HashContainer
{
std::size_t operator()(T const& Rhs) const
{
return boost::hash_range(Rhs.begin(), Rhs.end());
}
};
It is probably the best choice to use std::vector<int>
as your inner container, making the whole thing a boost::unordered_set<std::vector<int>, HashContainer<std::vector<int> > >
. 将
std::vector<int>
用作内部容器可能是最好的选择,从而使整个事情boost::unordered_set<std::vector<int>, HashContainer<std::vector<int> > >
。 Note that you do not necessarily need to use the same container for building and storing your inner sets. 请注意,您不一定需要使用相同的容器来构建和存储内部集。 If you want to use that you can either:
如果要使用它,则可以:
std::vector<int>
directly to build the inner sets. std::vector<int>
构建内部集。 For that, push all the values, then use std::sort
and std::unique
to establish set property, then insert into the outer set. std::sort
和std::unique
建立set属性,然后将其插入外部集合。 (Probably, preferred for performance) std::set<int>
and copy into a temporary vector, using the (Iterator, Iterator) constructor, in your insert call. std::set<int>
并在您的插入调用中使用(Iterator,Iterator)构造函数将其复制到一个临时向量中。 (This is the simplest code) boost::unordered_set<int>
, copy into a temporary vector, std::sort
that (no need for unique) and insert. boost::unordered_set<int>
,复制到一个临时向量std::sort
(不需要唯一)并插入。 You can also use std::set<int>
as the inner container, making the whole set an boost::unordered_set<std::set<int>, HashContainer<std::set<int> > >
. 您还可以使用
std::set<int>
作为内部容器,使整个集合成为boost::unordered_set<std::set<int>, HashContainer<std::set<int> > >
。 In this case, you can use any container to construct the inner sets. 在这种情况下,可以使用任何容器来构造内部集。 If you use
std::set<int>
you can move/copy into the outer container. 如果使用
std::set<int>
,则可以移动/复制到外部容器中。 I you use another container, you can use the std::set<int>::set(Iterator b, Iterator e)
constructor. 我使用另一个容器,则可以使用
std::set<int>::set(Iterator b, Iterator e)
构造函数。
Note that having C++11 move semantics available can be a huge performance win here, but in that case you should use the same container for constructing and storing the inner set. 请注意,拥有C ++ 11移动语义可以在这里获得巨大的性能胜利,但是在那种情况下,您应该使用相同的容器来构造和存储内部集合。
I don't have enough REPs to comment on the accepted answer. 我的REP不足,无法对接受的答案发表评论。 But I saw this in the boost docs about hash_range
但是我在关于hash_range的增强文档中看到了这一点
"hash_range is sensitive to the order of the elements so it wouldn't be appropriate to use this with an unordered container." “ hash_range对元素的顺序很敏感,因此将其与无序容器一起使用是不合适的。”
Using unordered
containers is all about hashing and every type that you use as a key should have an assigned hash function(and of course operator==
) in order to be used as a key in unordered
container. 使用
unordered
容器与散列有关,并且您用作键的每种类型都应具有分配的哈希函数(当然还有operator==
),以便用作unordered
容器中的键。 So when you use unordered_set<int>
as key for another unordered_set
you must provide a hash function for it. 因此,当您将
unordered_set<int>
用作另一个unordered_set
键时,必须为其提供哈希函数。 see <boost/functional/hash.hpp>
for more information on providing a hash function for a type 有关为类型提供哈希函数的更多信息,请参见
<boost/functional/hash.hpp>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.