散列容器(hash container):
通常比二叉树的存储方式可以提供更高的访问效率.
#include
#include
using namespace boost;
散列集合简介:
unordered库提供两个散列集合类unordered_set和unordered_multiset,STLport也提供hash_set和hash_multiset,它们的接口,用法与stl里的标准关联容器set/multiset相同,只是内部使用散列表代替了二叉树实现,因此查找复杂度由数降为常数。
unordered_set/unordered_multiset简要声明:
template
class Pred = std::equal_to
class Alloc = std::allocator
class unordered_set;
template
class Pred = std::equal_to
class Alloc = std::allocator
class unordered_multiset;
与std::set相比,unorder_set的模板增加了一个计算散列值的模板类型参数,通常是boost::hash,最好不要去改变它,另外比较谓词参数使用std::equal_to<>,而不是set中的less<>,这是因为散列容器不需要保持有序。
散列集合的用法:
注意散列容器的无序性,不能再散列容器上使用binary_search,lower_bound和upper_bound这样用于已序区间的算法,散列容器自身也不提供这样的成员函数。
示范:程序定义了一个模板函数hash_func(),用以操作hash_set/unordered_set,两者的表现是完全一样的,首先使用boost::assign初始化散列集合,以迭代器遍历输出,然后用size()显示容器大小,用clear()清空集合,再用insert()插入两个元素,用find()查找元素,最后用erase()删除一个元素,这些都是标准容器的标准操作。
#include
#include
#include
#include
using namespace boost;
using namespace std;
template
void hash_func()
{
using namespace boost::assign;
T s = (list_of(1), 2, 3, 4, 5); //初始化数据
for (T::iterator p = s.begin(); p != s.end(); ++p) //使用迭代器遍历集合
{ cout<< *p<<" "; }
cout<
cout<
s.insert(45);
cout<
}
int main()
{
hash_func
system("pause");
return 0;
}
散列映射简介:
unordered库提供两个散列映射类undorderd_map和unordered_multimap,它们的接口,用法与stl里的标准关联容器map/multimap相同,只是内部使用散列表代替了二叉树,模板参数多了散列计算函数,比较谓词使用equal_to<>。
unordered_map和unordered_multimap的简要声明:
template
class Pred = std::equal_to
class Alloc = std::allocator
class unordered_map;
template
class Pred = std::equal_to
class Alloc = std::allocator
class unordered_multimap;
散列映射的用法:
unordered_map/unordered_multimap属于关联式容器,采用std::pair保存key-value形式的数据,可以理解一个关联数组,提供operator[]重载,用法与标准容器map相同.
unordered_multimap允许有重复的key-value映射,因此不提供operator[].
示范:
#include
#include
#include
#include
#include
using namespace boost;
using namespace std;
using namespace stdext;
int main()
{
using namespace boost::assign;
//使用assign初始化
unordered_map
um.insert(make_pair(10, "ten"));
cout<
um[15] = "fifteen";
for (BOOST_AUTO(p, um.begin()); p != um.end(); ++p)
cout<
cout<
cout<
for (BOOST_AUTO(p, hmbegin()); p != hm.end(); ++p)
cout<
cout<
return 0;
}
性能比较:
示范:程序使用boost随机库random()向容器插入10000个1到100之间的整数,然后执行count和find操作;
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace boost;
using namespace std;
using namespace stdext;
template
void fill_set(T &c)
{
variate_generator
for (int i = 0; i < 10000; ++i)//插入一万个整数
c.insert(gen());
}
template
void test_perform()
{
T c;
cout<
boost::progress_timer t;
fill_set(c);
}
{
boost::progress_timer t;
c.count(10);
}
{
boost::progress_timer t;
c.find(20);
}
}
int main()
{
test_perform
//test_perform
test_perform
system("pause");
return 0;
}
高级议题:
内部数据结构:
unordered库使用“桶(bucket)”来存储元素,散列值相同的元素被放入同一个桶中,当前散列容器的桶的数量可以用成员函数bucket_count()来获得,bucket_size()返回桶中的元素数量,例如:
unordered_set
cout<< us.bucket_count()<
{cout<
unordered_set
us.rehash(200);//使用200个桶
c++0x RT1草案还规定有一个函数max_load_factor(),它可以获取或设定散列容器的最大负载因子,即桶中元素的最大平均数量,通常最大负载因子都是1,用户不应当去改变它,过大或过小都没有意义。
支持自定义类型:
unordered库支持c++内建类型和大多数标准库容器,但不支持用户自定义的类型,因为它无法计算自定义类型的散列值。
如果要使unordered支持自定义类型,需要定制类模板的第二个和第三个参数,也就是供散列函数和相等比较谓词。
相等比较谓词,unordered库默认使用std::equal_to,这是一个标准库中的函数对象,它使用operator==,只有自定义类实现了这个操作符就可以了,不必再特意编写一个函数对象,如果需要用一个特别的相等判断规则,那么可以额外写函数对象,传递给unordered容器。
散列函数则是必须要实现的,这也是为什么它被放在模板参数列表前面的原因,我们需要使用boost.hash库来计算自定义类型的散列值,组简单的使用方法是编写一个hash_value()函数,创建一个hash函数对象,然后使用它的operator()返回散列值。
下面的代码定义了一个类demo_class,它实现了operator==和散列函数,可以被unordered所容纳:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace boost;
using namespace std;
using namespace stdext;
using namespace boost::assign;
struct demo_class
{
int a;
friend bool operator==(const demo_class& l, const demo_class& r)
{ return l.a == r.a; }
};
size_t hash_value(demo_class & s)
{ return boost::hash
int main() system("pause");
{
unordered_set
demo_class a1;
a1.a =100;
cout<
a2.a =100;
cout<
return 0;
}
与TR1的差异:
boost.unordered基本上依据c++0x标准草案来实现,但它有个小的”扩充“,增加了比较操作符operator==和operator !=;注意:这两个操作符不属于c++0x标准,如果将来程序要切换到新标准可能会遇到不可用移植的问题。