boost.unordered 基于hash table的四种容器(即hash_map,unordered_mutimap,hash_set,hash_multiset)

boost.unordered  即基于hash table的四种容器(即hash_map,unordered_mutimap,hash_set,hash_multiset)

接口类似于std:map      std::multimap,         std::set,.   std::mutiset

 boost::unordered_map, 它与 stl::map的区别就是:stl::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中。所以,如果对map进行遍历(中序遍历)的话,输出的结果是有序的。顺序就是按照operator< 定义的大小排序。

而boost::unordered_map是计算元素的Hash值,根据Hash值判断元素是否相同。所以,对unordered_map进行遍历,结果是无序的。

用法的区别就是,stl::map 的key需要定义operator< 。 而boost::unordered_map需要定义hash_value函数并且重载operator==。对于内置类型,如string,这些都不用操心。对于自定义的类型做key,就需要自己重载operator< 或者hash_value()了。 

最后,说,当不需要结果排好序时,最好用unordered_map。


散列容器(hash container)是一种非常重要的容器类型,它通常比二叉树的存储方式可以提供更高的访问效率。C++98标准中并未规定散列容器,因为它的提案来得太晚了,但这并不


妨碍编译器厂商实现自己的散列容器。SGISTL、STLport、Dinknumware STL等实现都向用 户提供了各自的散列容器。

由于散列容器没有标准规范,各家的实现也就各不相同,性能、接口也有差异,不过在容器 的名字上倒是难得的一致,基本都是hash_map、hash_set。

等到C++标准委员会有了时间,开始整理散列容器的标准时,这才发现,数年间非标准实现 已经广泛流传,接近“事实上的标准”,标准的名字hash_xxx已经被“鸠占鹊巢”。因此,C+ + 标准委员会不得不选用了另一个unordered—xxx以避免与现存代码冲突,不过这个名字也更好地表现了散列容器的本质——它是无序的。

因为散列容器是无序的,因此不需要容器的元素类型提供operator而是使用散列函数和 键值比较的0Perat0r==,比标准容器的要求要略微放宽一些。

boost .unordered库提供了一个完全符合C++新标准草案(TR1)的散列容器实现,包括无序集合(set)和无序映射(map)。它们位于名字空间boost,为使用unordered库,需要包含头文件<boost/unordered_set.hpp>

#include<boost/unordered_map • hpp>

#include<boost/unordered_set.hpp>

#include <boost/unordered_map.hpp>

using namespace boost;

由于STLport中也提供了散列容器的实现,故这里将同unordered—起对比介绍。

散列容器(hash container):
通常比二叉树的存储方式可以提供更高的访问效率.
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
using namespace boost;
散列集合简介:
unordered库提供两个散列集合类unordered_set和unordered_multiset,STLport也提供hash_set和hash_multiset,它们的接口,用法与stl里的标准关联容器set/multiset相同,只是内部使用散列表代替了二叉树实现,因此查找复杂度由数降为常数。

unordered_set/unordered_multiset简要声明:
template<class Key, class Hash = boost::hash<Key>,//
 class Pred = std::equal_to<Key>,
 class Alloc = std::allocator<Key>>
class unordered_set;

template<class Key, class Hash = boost::hash<Key>,
 class Pred = std::equal_to<Key>,
 class Alloc = std::allocator<Key>>
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 <iostream>
#include <hash_set>   //STLport的散列集合
#include <boost/unordered_set.hpp>   //boost的散列集合
#include <boost/assign/list_of.hpp>//
using namespace boost;
using namespace std;
template<typename T>    //模板参数要求为散列集合类型
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<<endl;
 cout<<s.size()<<endl;
 s.clear();             //清空集合
 cout<<s.empty()<<endl;  //判断集合为空
 s.insert(8);    //通标准库一样使用insert()函数
 s.insert(45);
 cout<<s.size()<<endl;
 cout<<*s.find(8)<<endl;
 s.erase(45);
}

int main()
{
 hash_func<unordered_set<int>>();
 system("pause");
 return 0;
}
散列映射简介:
unordered库提供两个散列映射类undorderd_map和unordered_multimap,它们的接口,用法与stl里的标准关联容器map/multimap相同,只是内部使用散列表代替了二叉树,模板参数多了散列计算函数,比较谓词使用equal_to<>。
unordered_map和unordered_multimap的简要声明:

template<class Key, class Mapped,
 class Hash = boost::hash<Key>,
 class Pred = std::equal_to<Key>,
 class Alloc = std::allocator<Key>>
class unordered_map;

template<class Key, class Mapped,
 class Hash = boost::hash<Key>,
 class Pred = std::equal_to<Key>,
 class Alloc = std::allocator<Key>>
class unordered_multimap;
散列映射的用法:
unordered_map/unordered_multimap属于关联式容器,采用std::pair保存key-value形式的数据,可以理解一个关联数组,提供operator[]重载,用法与标准容器map相同.
unordered_multimap允许有重复的key-value映射,因此不提供operator[].
示范:
#include <iostream>
#include <hash_map>
#include <boost/unordered_map.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/typeof/typeof.hpp>
using namespace boost;
using namespace std;
using namespace stdext; 
int main()
{
 using namespace boost::assign;   //使用assign初始化
 unordered_map<int, string> um = map_list_of(1, "one")(2, "two")(3, "three");
 um.insert(make_pair(10, "ten"));  //可以使用insert函数
 cout<<um[10]<<endl;      //使用operator[]访问元素
 um[11] = "eleven";    //关联数组用法
 um[15] = "fifteen";
 for (BOOST_AUTO(p, um.begin()); p != um.end(); ++p)   //使用BOOST_AUTO获得迭代器
  cout<<p->first<<"-"<<p->second<<",";
 cout<<endl;
 um.erase(11);   //删除键值为11的元素
 cout<<um.size()<<endl;  //输出5
 hash_map<int, string> hm = map_list_of(4, "four")(5, "five")(6, "six");  //STLport提供的散列映射类
 for (BOOST_AUTO(p, hmbegin()); p != hm.end(); ++p)   //迭代器遍历
  cout<<p->first<<"-"<<p->second<<",";
 cout<<endl;
 system("pause");
 return 0;
}

性能比较:
示范:程序使用boost随机库random()向容器插入10000个1到100之间的整数,然后执行count和find操作;

#include <iostream>
#include <typeinfo>
#include <hash_map>
#include <set>
#include <boost/unordered_set.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/random.hpp>
#include <boost\Progress.hpp>
using namespace boost;
using namespace std;
using namespace stdext;

template<typename T>
void fill_set(T &c)
{
 variate_generator<mt19937, uniform_int<>> gen(mt19937(), uniform_int<>(0, 100));
 for (int i = 0; i < 10000; ++i)//插入一万个整数
  c.insert(gen());
}
template<typename T>
void test_perform()
{
 T c;
 cout<<typeid(c).name()<<endl;
 {
  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<multiset<int>>();
 //test_perform<hash_multiset<int>>();
 test_perform<unordered_multiset<int>>();
 system("pause");
 return 0;
}

高级议题:
内部数据结构:
unordered库使用“桶(bucket)”来存储元素,散列值相同的元素被放入同一个桶中,当前散列容器的桶的数量可以用成员函数bucket_count()来获得,bucket_size()返回桶中的元素数量,例如:
unordered_set<int> us = (list_of(1), 2, 3, 4);
cout<< us.bucket_count()<<endl;
for(int i = 0; i < us.bucket_count(); ++i)//访问每个桶
{cout<<us.bucket_size(i)<<",";}
当散列容器中有大量数据时,桶中的元素数量也会增多,会造成访问冲突。为了提高散列容器的性能,unordered库会在插入元素时自动增加桶的数量,用户不能直接指定桶的数量,但可以在构造函数或者rehash()函数指定最小的桶的数量。例如:
unordered_set<int> us(100);//使用100个桶存储数据
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 <iostream>
#include <typeinfo>
#include <hash_map>
#include <set>
#include <boost/unordered_set.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/random.hpp>
#include <boost/Progress.hpp>
#include <boost/functional/hash.hpp>
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>()(s.a);}

int main()
{
unordered_set<demo_class> us;
demo_class a1;
a1.a =100;
cout<<hash_value(a1)<<endl;
demo_class a2;
a2.a =100;
cout<<hash_value(a2)<<endl;

system("pause");
return 0;
}
与TR1的差异:
boost.unordered基本上依据c++0x标准草案来实现,但它有个小的”扩充“,增加了比较操作符operator==和operator !=;注意:这两个操作符不属于c++0x标准,如果将来程序要切换到新标准可能会遇到不可用移植的问题。

BOOST中unordered_map用法示例

#include<string>
#include<iostream>

#include<boost/unordered_map.hpp>

using namespace std;

struct person
{
	string name;
	int age;

	person(string name, int age)
	{
		this->name =  name;
		this->age = age;
	}

	bool operator== (const person& p) const
	{
		return name==p.name && age==p.age;
	}
};

size_t hash_value(const person& p)
{
	size_t seed = 0;
	boost::hash_combine(seed, boost::hash_value(p.name));
	boost::hash_combine(seed, boost::hash_value(p.age));
	return seed;
}

int main()
{
	typedef boost::unordered_map<person,int> umap;
	umap m;
	person p1("Tom1",20);
	person p2("Tom2",22);
	person p3("Tom3",22);
	person p4("Tom4",23);
	person p5("Tom5",24);
	m.insert(umap::value_type(p3, 100));
	m.insert(umap::value_type(p4, 100));
	m.insert(umap::value_type(p5, 100));
	m.insert(umap::value_type(p1, 100));
	m.insert(umap::value_type(p2, 100));
	
	for(umap::iterator iter = m.begin(); iter != m.end(); iter++)
	{
		cout<<iter->first.name<<"\t"<<iter->first.age<<endl;
	}
	
	return 0;
}

BOOST中unordered_set用法示例

#include <boost/unordered_set.hpp>
#include <boost/assign.hpp>
#include <boost/typeof/typeof.hpp>

using namespace boost;
using namespace std;

template<typename T>
void hash_func()
{
  T s = (boost::assign::list_of(1),2,3,4,5);  /* 初始化数据 */
  for (BOOST_AUTO(p, s.begin()); p != s.end(); ++p)
  //for (T::iterator p = s.begin(); p!= s.end(); ++p)
  {
     cout << *p << " "; 
  }
  cout << endl;
  cout << s.size() << endl;

  s.clear();
  cout << s.empty() << endl;
  s.insert(8);
  s.insert(45);
  cout << s.size() << endl;
  cout << *s.find(8) << endl;

  s.erase(45);
}

int main(void)
{
   //hash_func<ext::hash_set<int> >();   /* stlport的hash_set 偶没安装 */
   hash_func<unordered_set<int> >();
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值