简体   繁体   English

在C ++中将常规`set`转换为boost'`unordered_set`

[英]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: 我乐观地认为,从setunordered_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::vectorstd::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: 如果要使用它,则可以:

  • Use 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::sortstd::unique建立set属性,然后将其插入外部集合。 (Probably, preferred for performance) (可能是性能的首选)
  • Use 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) (这是最简单的代码)
  • Use 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM