unordered容器

1.散列容器(hash container)

   散列容器一般比二叉樹的存儲方式能夠提供更高的訪問效率.ios

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相同,只是內部使用散列表代替了二叉樹實現,所以查找複雜度由數降爲常數。c++

  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的簡要聲明:app

 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[].
  示範:less

 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 }

  性能比較:dom

  示範:程序使用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 <boost\Progress.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標準,若是未來程序要切換到新標準可能會遇到不可用移植的問題。

相關文章
相關標籤/搜索