zoukankan      html  css  js  c++  java
  • unordered容器

    1.散列容器(hash container)

       散列容器通常比二叉树的存储方式可以提供更高的访问效率.

    1 #include <boost/unordered_set.hpp>
    2 #include <boost/unordered_map.hpp>
    3 using namespace boost;

    2.散列集合简介

      unordered库提供两个散列集合类unordered_set和unordered_multiset,STLport也提供hash_set和hash_multiset,它们的接口,用法与stl里的标准关联容器set/multiset相同,只是内部使用散列表代替了二叉树实现,因此查找复杂度由数降为常数。

      unordered_set/unordered_multiset简要声明:

    1 template<class Key, class Hash = boost::hash<Key>,
    2  class Pred = std::equal_to<Key>,
    3  class Alloc = std::allocator<Key>>
    4 class unordered_set;
    5 
    6 template<class Key, class Hash = boost::hash<Key>,
    7  class Pred = std::equal_to<Key>,
    8  class Alloc = std::allocator<Key>>
    9 class unordered_multiset;

      与std::set相比,unorder_set的模板增加了一个计算散列值的模板类型参数,通常是boost::hash,最好不要去改变它,另外比较谓词参数使用std::equal_to<>,而不是set中的less<>,这是因为散列容器不需要保持有序。

    3.散列集合的用法

      注意散列容器的无序性,不能再散列容器上使用binary_search,lower_bound和upper_bound这样用于已序区间的算法,散列容器自身也不提供这样的成员函数。
      示范:程序定义了一个模板函数hash_func(),用以操作hash_set/unordered_set,两者的表现是完全一样的,首先使用boost::assign初始化散列集合,以迭代器遍历输出,然后用size()显示容器大小,用clear()清空集合,再用insert()插入两个元素,用find()查找元素,最后用erase()删除一个元素,这些都是标准容器的标准操作。

     1 #include <iostream>
     2 #include <hash_set>
     3 #include <boost/unordered_set.hpp>
     4 #include <boost/assign/list_of.hpp>
     5 using namespace boost;
     6 using namespace std;
     7 template<typename T>
     8 void hash_func()
     9 {
    10    using namespace boost::assign;
    11 
    12    T s = (list_of(1), 2, 3, 4, 5);   //初始化数据
    13    for (T::iterator p = s.begin(); p != s.end(); ++p) //使用迭代器遍历集合
    14    { cout<< *p<<" "; }
    15 
    16    cout<<endl;
    17    cout<<s.size()<<endl;
    18 
    19    s.clear();
    20    cout<<s.empty()<<endl;
    21 
    22    s.insert(8);
    23    s.insert(45);
    24 
    25    cout<<s.size()<<endl;
    26    cout<<*s.find(8)<<endl;
    27 
    28    s.erase(45);
    29 }
    30 
    31 int main()
    32 {
    33    hash_func<unordered_set<int>>();
    34 
    35    system("pause");
    36    return 0;
    37 }

    4.散列映射简介

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

     1 template<class Key, class Mapped,
     2  class Hash = boost::hash<Key>,
     3  class Pred = std::equal_to<Key>,
     4  class Alloc = std::allocator<Key>>
     5 class unordered_map;
     6 
     7 template<class Key, class Mapped,
     8  class Hash = boost::hash<Key>,
     9  class Pred = std::equal_to<Key>,
    10  class Alloc = std::allocator<Key>>
    11 class unordered_multimap;

    5.散列映射的用法

      unordered_map/unordered_multimap属于关联式容器,采用std::pair保存key-value形式的数据,可以理解一个关联数组,提供operator[]重载,用法与标准容器map相同.
      unordered_multimap允许有重复的key-value映射,因此不提供operator[].
      示范:

     1 #include <iostream>
     2 #include <hash_map>
     3 #include <boost/unordered_map.hpp>
     4 #include <boost/assign/list_of.hpp>
     5 #include <boost/typeof/typeof.hpp>
     6 using namespace boost;
     7 using namespace std;
     8 using namespace stdext; 
     9 int main()
    10 {
    11    using namespace boost::assign;
    12 
    13    //使用assign初始化
    14    unordered_map<int, string> um = map_list_of(1, "one")(2, "two")(3, "three");
    15 
    16    um.insert(make_pair(10, "ten"));
    17    cout<<um[10]<<endl;
    18 
    19    um[11] = "eleven";
    20    um[15] = "fifteen";
    21    for (BOOST_AUTO(p, um.begin()); p != um.end(); ++p)
    22       cout<<p->first<<"-"<<p->second<<",";
    23    cout<<endl;
    24 
    25    um.erase(11);
    26    cout<<um.size()<<endl;
    27 
    28    hash_map<int, string> hm = map_list_of(4, "four")(5, "five")(6, "six");
    29    for (BOOST_AUTO(p, hmbegin()); p != hm.end(); ++p)
    30       cout<<p->first<<"-"<<p->second<<",";
    31    cout<<endl;
    32 
    33    system("pause");
    34    return 0;
    35 }

      性能比较:

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

     1 #include <iostream>
     2 #include <typeinfo>
     3 #include <hash_map>
     4 #include <set>
     5 #include <boost/unordered_set.hpp>
     6 #include <boost/assign/list_of.hpp>
     7 #include <boost/typeof/typeof.hpp>
     8 #include <boost/random.hpp>
     9 #include <boostProgress.hpp>
    10 using namespace boost;
    11 using namespace std;
    12 using namespace stdext;
    13 
    14 template<typename T>
    15 void fill_set(T &c)
    16 {
    17    variate_generator<mt19937, uniform_int<>> gen(mt19937(), uniform_int<>(0, 100));
    18    for (int i = 0; i < 10000; ++i)//插入一万个整数
    19     c.insert(gen());
    20 }
    21 template<typename T>
    22 void test_perform()
    23 {
    24    T c;
    25    cout<<typeid(c).name()<<endl;
    26    {
    27       boost::progress_timer t;
    28       fill_set(c);
    29    }
    30    {
    31       boost::progress_timer t;
    32       c.count(10);
    33    }
    34    {
    35       boost::progress_timer t;
    36       c.find(20);
    37    }
    38 }
    39 
    40 int main()
    41 {
    42    test_perform<multiset<int>>();
    43    //test_perform<hash_multiset<int>>();
    44    test_perform<unordered_multiset<int>>();
    45    system("pause");
    46    return 0;
    47 }

      高级议题:

      内部数据结构:
       unordered库使用“桶(bucket)”来存储元素,散列值相同的元素被放入同一个桶中,当前散列容器的桶的数量可以用成员函数bucket_count()来获得,bucket_size()返回桶中的元素数量,例如:

    1 unordered_set<int> us = (list_of(1), 2, 3, 4);
    2 cout<< us.bucket_count()<<endl;
    3 for(int i = 0; i < us.bucket_count(); ++i)//访问每个桶
    4 {cout<<us.bucket_size(i)<<",";}

      当散列容器中有大量数据时,桶中的元素数量也会增多,会造成访问冲突。为了提高散列容器的性能,unordered库会在插入元素时自动增加桶的数量,用户不能直接指定桶的数量,但可以在构造函数或者rehash()函数指定最小的桶的数量。例如:

    1 unordered_set<int> us(100);//使用100个桶存储数据
    2 us.rehash(200);//使用200个桶

      c++0x RT1草案还规定有一个函数max_load_factor(),它可以获取或设定散列容器的最大负载因子,即桶中元素的最大平均数量,通常最大负载因子都是1,用户不应当去改变它,过大或过小都没有意义。

      支持自定义类型:
         1)unordered库支持c++内建类型和大多数标准库容器,但不支持用户自定义的类型,因为它无法计算自定义类型的散列值。
         2)如果要使unordered支持自定义类型,需要定制类模板的第二个和第三个参数,也就是供散列函数和相等比较谓词。
         3)相等比较谓词,unordered库默认使用std::equal_to,这是一个标准库中的函数对象,它使用operator==,只有自定义类实现了这个操作符就可以了,不必再特意编写一个函数对象,如果需要用一个特别的相等判断规则,那么可以额外写函数对象,传递给unordered容器。
         4)散列函数则是必须要实现的,这也是为什么它被放在模板参数列表前面的原因,我们需要使用boost.hash库来计算自定义类型的散列值,组简单的使用方法是编写一个hash_value()函数,创建一个hash函数对象,然后使用它的operator()返回散列值。
      下面的代码定义了一个类demo_class,它实现了operator==和散列函数,可以被unordered所容纳:

     1 #include <iostream>
     2 #include <typeinfo>
     3 #include <hash_map>
     4 #include <set>
     5 #include <boost/unordered_set.hpp>
     6 #include <boost/assign/list_of.hpp>
     7 #include <boost/typeof/typeof.hpp>
     8 #include <boost/random.hpp>
     9 #include <boost/Progress.hpp>
    10 #include <boost/functional/hash.hpp>
    11 using namespace boost;
    12 using namespace std;
    13 using namespace stdext;
    14 using namespace boost::assign;
    15 struct demo_class
    16 {
    17    int a;
    18    friend bool operator==(const demo_class& l, const demo_class& r)
    19    {  return l.a == r.a; }
    20 };
    21 
    22 size_t hash_value(demo_class & s)
    23 { return boost::hash<int>()(s.a);}
    24 
    25 int main()
    26 {
    27    unordered_set<demo_class> us;
    28 
    29    demo_class a1;
    30    a1.a =100;
    31    cout<<hash_value(a1)<<endl;
    32 
    33    demo_class a2;
    34    a2.a =100;
    35    cout<<hash_value(a2)<<endl;
    36 
    37    system("pause");
    38    return 0;
    39 }

      与TR1的差异:

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

  • 相关阅读:
    scrapy_redis对接布隆过滤器(Bloom Filter)
    Python-Scrapy shell 带头部headers请求
    postgres数据库入门, python 操作postgres
    Windows下安装MySQL详细教程
    在读取文件中出现ufeff,解决 ufeff的问题
    scrapy中主动停止爬虫
    Scrapy 中Filtered offsite request to 'www.sohu.com':报错的解决方法
    win10系统谷歌插件此扩展程序可能已损坏的解决方法
    如何将已经安装从chrome扩展程序导出备份为.CRX文件?
    PAC模式和全局模式的区别
  • 原文地址:https://www.cnblogs.com/blueoverflow/p/4925541.html
Copyright © 2011-2022 走看看