我有一个小程序,主要使用常规set
,但现在我的表现不佳,我决定使用来自boost的unordered_set
。我乐观地认为,从set
到unordered_set
进行简单的搜索和替换可以解决其他标题,例如:
#include <boost/unordered_set.hpp>
using boost::unordered_set;
但现在我有很多编译错误。我已经研究过并意识到即使是简单的嵌套for
循环也不起作用。这是一个例子:
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;
}
}
在使用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)
以及使用unordered_set
时的更多内容。我错过了什么?
答案 0 :(得分:3)
您缺少unordered_sets的哈希函数。坏消息是,你不能轻易地构建一个。例如,您插入内部集合的顺序可能会导致容器内的顺序不同,因此如果您使用天真的方式构造它,则会产生不同的哈希(正如我在此答案的先前版本中所做的那样:))
无论哪种方式,您都需要为内部集合选择不同的容器,并且需要对这些集合进行排序。我建议您使用std::vector
或std::set
。然后你需要一个哈希函子:你可以使用boost::hash_range
轻松构造一个:
template <class T>
struct HashContainer
{
std::size_t operator()(T const& Rhs) const
{
return boost::hash_range(Rhs.begin(), Rhs.end());
}
};
使用std::vector<int>
作为内部容器可能是最佳选择,使整个事件成为boost::unordered_set<std::vector<int>, HashContainer<std::vector<int> > >
。
请注意,您不一定需要使用相同的容器来构建和存储内部集。如果你想使用它,你可以:
std::vector<int>
构建内部集。为此,推送所有值,然后使用std::sort
和std::unique
建立set属性,然后插入外部集合。 (可能是性能的首选)std::set<int>
并使用(Iterator,Iterator)构造函数在插入调用中复制到临时向量中。 (这是最简单的代码)boost::unordered_set<int>
,复制到临时向量std::sort
(不需要唯一)并插入。您还可以使用std::set<int>
作为内部容器,使整个集合成为boost::unordered_set<std::set<int>, HashContainer<std::set<int> > >
。在这种情况下,您可以使用任何容器来构造内部集。如果使用std::set<int>
,则可以移动/复制到外部容器中。我使用另一个容器,你可以使用std::set<int>::set(Iterator b, Iterator e)
构造函数。
请注意,使用C ++ 11移动语义可以获得巨大的性能,但在这种情况下,您应该使用相同的容器来构造和存储内部集合。
答案 1 :(得分:2)
我没有足够的REP来评论接受的答案。 但我在关于hash_range
的提升文档中看到了这一点“hash_range对元素的顺序很敏感,因此不适合使用 这是一个无序的容器。“
答案 2 :(得分:1)
使用unordered
容器是关于散列的,并且您用作密钥的每种类型都应该具有指定的散列函数(当然还有operator==
),以便在{{中用作密钥1}}容器。因此,当您使用unordered
作为另一个unordered_set<int>
的密钥时,您必须为其提供哈希函数。有关为类型
unordered_set