转自http://blog.csdn.net/mmzsyx/article/details/8240071

散列容器(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>
#include <boost/unordered_set.hpp>
#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);
 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"));
 cout<<um[10]<<endl;
 um[11] = "eleven";
 um[15] = "fifteen";
 for (BOOST_AUTO(p, um.begin()); p != um.end(); ++p)
  cout<<p->first<<"-"<<p->second<<",";
 cout<<endl;
 um.erase(11);
 cout<<um.size()<<endl;
 hash_map<int, string> hm = map_list_of(4, "four")(5, "five")(6, "six");
 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标准,如果将来程序要切换到新标准可能会遇到不可用移植的问题。

unorder_set<typename T> 学习的更多相关文章

  1. effective c++ 笔记 (41-44)

    //---------------------------15/04/25---------------------------- //#41   了解隐式接口和编译期多态 { //  1:面向对象编 ...

  2. Torch7学习笔记(二)nn Package

    神经网络Package [目前还属于草稿版,等我整个学习玩以后会重新整理] 模块Module module定义了训练神经网络需要的所有基础方法,并且是可以序列化的抽象类. module有两种状态变量: ...

  3. Retrofit 入门学习

    Retrofit 入门学习官方RetrofitAPI 官方的一个例子 public interface GitHubService { @GET("users/{user}/repos&qu ...

  4. C++学习笔记(2)

    本学习笔记是C++ primer plus(第六版)学习笔记.是C++学习笔记(1)的后续.复习C++基础知识的可以瞄瞄. 转载请注明出处http://www.cnblogs.com/zrtqsk/p ...

  5. C++学习笔记(1)

    本学习笔记是C++ primer plus(第六版)学习笔记.复习C++基础知识的可以瞄瞄. 转载请注明出处http://www.cnblogs.com/zrtqsk/p/3874148.html,谢 ...

  6. C++中typename和class的区别

    C++中typename和class的区别 在c++Template中很多地方都用到了typename与class这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢? 相信学习C++的人对c ...

  7. Spring学习总结(五)——Spring整合MyBatis(Maven+MySQL)一

    MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中. 使用这个类库中的类, Spring 将会加载必要的MyBatis工厂类和 session 类. 这个类库 ...

  8. 【zepto学习笔记03】事件机制

    前言 我们今天直接进入事件相关的学习,因为近期可能会改到里面的代码就zepto来说,我认为最重要的就是选择器与事件相关了,随着浏览器升级,选择器简单了,而事件相关仍然是核心,今天我们就来学习学习 ze ...

  9. Caffe学习系列(15):添加新层

    如何在Caffe中增加一层新的Layer呢?主要分为四步: (1)在./src/caffe/proto/caffe.proto 中增加对应layer的paramter message: (2)在./i ...

随机推荐

  1. WCF_基础学习

    1.https://www.cnblogs.com/swjian/p/8126202.html 2.https://www.cnblogs.com/dotnet261010/p/7407444.htm ...

  2. Docker 学习基本操作与守护式容器

    Docker 学习基本操作与守护式容器 容器操作 运行容器 docker run --name指定名字 -istdin -ttty虚拟终端 在终端中用 exit 即可退出容器,并结束运行 查看容器 p ...

  3. Git下的gitignore规则介绍

    匹配模式前/代表项目根目录 匹配模式最后加/代表是目录 匹配模式前加!代表取反 (忽略文件夹,但不忽略文件夹下的某个文件) *代表任意个字符 ? 匹配任意一个字符 **匹配多级目录 node_modu ...

  4. 在VUE中,关于CKEditor使用

    官方文档 语言配置 代码如下 ClassicEditor .create( document.querySelector( '#editor' ), { language: 'de' // 配置语言 ...

  5. 【android】android对位图文件的支持

    Android 支持以下三种格式的位图文件:.png(首选)..jpg(可接受)..gif(不建议).

  6. 【mysql】The server quit without updating PID file

      groupadd mysql useradd -r -g mysql mysql cd /usr/local/mysql chown -R mysql:mysql . scripts/mysql_ ...

  7. STM32CUBEMX入门学习笔记3:HAL库以及STM32CUBE相关资料

    微雪课堂:http://www.waveshare.net/study/article-629-1.html 之前的正点原子的例程资料 硬石科技stm32cube: 链接:https://pan.ba ...

  8. i2c drivers

    Linux设备驱动程序架构分析之一个I2C驱动实例   转载于:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1   编写一个I2C设备驱动程序的工作可分为两部分 ...

  9. 树状数组:CDOJ1583-曜酱的心意(树状数组心得)

    曜酱的心意 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 131072/131072KB (Java/Others) Description ...

  10. mac常用软件,自用找了很久的分享一下相信很多人需要

    CleanMyMac 3.1.1.dmg比较好用的清理软件.破解版!http://pan.baidu.com/s/1i4mo7jvNTFS读写 Tuxera NTFS for Mac.rar也是破解的 ...