C++(STL):33---hash_set、hash_map、hash_multiset、hash_multimap源码剖析

  • 这些关联容器底层都是使用hash table实现的.

一、hash_set

  •  由于hash_set底层是以hash table实现的,因此hash_set只是简单的调用hash table的方法即可

  • 与set的异同点:

    • hash_set与set都是用来快速查找元素的

    • 但是set会对元素自动排序,而hash_set没有

    • hash_set和set的使用方法相同

  • 在介绍hash table的hash functions的时候说过,hash table有一些无法处理的类型(除非用户自己书写hash function)。因此hash_set也无法自己处理

hash_set源码

//以下代码摘录于stl_hash_set.htemplate <class _Value, class _HashFcn, class _EqualKey, class _Alloc>class hash_set{// requirements:

__STL_CLASS_REQUIRES(_Value, _Assignable);__STL_CLASS_UNARY_FUNCTION_CHECK(_HashFcn, size_t, _Value);__STL_CLASS_BINARY_FUNCTION_CHECK(_EqualKey, bool, _Value, _Value);

private://indentity<>定义于<stl_function.h>中typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>,_EqualKey, _Alloc> _Ht;_Ht _M_ht; //底层以hash table实现

public:typedef typename _Ht::key_type key_type;typedef typename _Ht::value_type value_type;typedef typename _Ht::hasher hasher;typedef typename _Ht::key_equal key_equal;

typedef typename _Ht::size_type size_type;typedef typename _Ht::difference_type difference_type;typedef typename _Ht::const_pointer pointer;typedef typename _Ht::const_pointer const_pointer;typedef typename _Ht::const_reference reference;typedef typename _Ht::const_reference const_reference;

typedef typename _Ht::const_iterator iterator;typedef typename _Ht::const_iterator const_iterator;

typedef typename _Ht::allocator_type allocator_type;

hasher hash_funct() const { return _M_ht.hash_funct(); }key_equal key_eq() const { return _M_ht.key_eq(); }allocator_type get_allocator() const { return _M_ht.get_allocator(); }

public://缺省使用大小为100的表格,将被hash table调整为最接近且较大的质数hash_set(): _M_ht(100, hasher(), key_equal(), allocator_type()) {}explicit hash_set(size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()) {}hash_set(size_type __n, const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()) {}hash_set(size_type __n, const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a) {}

#ifdef __STL_MEMBER_TEMPLATEStemplate <class _InputIterator>hash_set(_InputIterator __f, _InputIterator __l): _M_ht(100, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }template <class _InputIterator>hash_set(_InputIterator __f, _InputIterator __l, size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }template <class _InputIterator>hash_set(_InputIterator __f, _InputIterator __l, size_type __n,const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }template <class _InputIterator>hash_set(_InputIterator __f, _InputIterator __l, size_type __n,const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a){ _M_ht.insert_unique(__f, __l); }#else

hash_set(const value_type* __f, const value_type* __l): _M_ht(100, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_set(const value_type* __f, const value_type* __l, size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_set(const value_type* __f, const value_type* __l, size_type __n,const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_set(const value_type* __f, const value_type* __l, size_type __n,const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a){ _M_ht.insert_unique(__f, __l); }

hash_set(const_iterator __f, const_iterator __l): _M_ht(100, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_set(const_iterator __f, const_iterator __l, size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_set(const_iterator __f, const_iterator __l, size_type __n,const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_set(const_iterator __f, const_iterator __l, size_type __n,const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a){ _M_ht.insert_unique(__f, __l); }#endif /*__STL_MEMBER_TEMPLATES */

public://所有操作几乎都有hash table的对应版本。传递调用即可size_type size() const { return _M_ht.size(); }size_type max_size() const { return _M_ht.max_size(); }bool empty() const { return _M_ht.empty(); }void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); }

#ifdef __STL_MEMBER_TEMPLATEStemplate <class _Val, class _HF, class _EqK, class _Al>friend bool operator== (const hash_set<_Val, _HF, _EqK, _Al>&,const hash_set<_Val, _HF, _EqK, _Al>&);#else /* __STL_MEMBER_TEMPLATES */friend bool __STD_QUALIFIERoperator== __STL_NULL_TMPL_ARGS (const hash_set&, const hash_set&);#endif /* __STL_MEMBER_TEMPLATES */

iterator begin() const { return _M_ht.begin(); }iterator end() const { return _M_ht.end(); }

public:pair<iterator, bool> insert(const value_type& __obj){pair<typename _Ht::iterator, bool> __p = _M_ht.insert_unique(__obj);return pair<iterator,bool>(__p.first, __p.second);}#ifdef __STL_MEMBER_TEMPLATEStemplate <class _InputIterator>void insert(_InputIterator __f, _InputIterator __l){ _M_ht.insert_unique(__f,__l); }#elsevoid insert(const value_type* __f, const value_type* __l) {_M_ht.insert_unique(__f,__l);}void insert(const_iterator __f, const_iterator __l){_M_ht.insert_unique(__f, __l); }#endif /*__STL_MEMBER_TEMPLATES */pair<iterator, bool> insert_noresize(const value_type& __obj){pair<typename _Ht::iterator, bool> __p =_M_ht.insert_unique_noresize(__obj);return pair<iterator, bool>(__p.first, __p.second);}

iterator find(const key_type& __key) const { return _M_ht.find(__key); }

size_type count(const key_type& __key) const { return _M_ht.count(__key); }

pair<iterator, iterator> equal_range(const key_type& __key) const{ return _M_ht.equal_range(__key); }

size_type erase(const key_type& __key) {return _M_ht.erase(__key); }void erase(iterator __it) { _M_ht.erase(__it); }void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }void clear() { _M_ht.clear(); }

public:void resize(size_type __hint) { _M_ht.resize(__hint); }size_type bucket_count() const { return _M_ht.bucket_count(); }size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }size_type elems_in_bucket(size_type __n) const{ return _M_ht.elems_in_bucket(__n); }};

template <class _Value, class _HashFcn, class _EqualKey, class _Alloc>inline booloperator==(const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs1,const hash_set<_Value,_HashFcn,_EqualKey,_Alloc>& __hs2){return __hs1._M_ht == __hs2._M_ht;}

hash_set使用演示案例

  • hash_set并不会对元素进行排序

  • 下面演示在hash_set中存储字符串

#include <iostream>#include <hash_set>#include <string.h>using namespace std;

struct eqstr{bool operator()(const char* s1, const char* s2){return strcmp(s1, s2) == 0;}};

void loopup(const hash_set<const char*, hash<const char*>, eqstr>& Set,const char* word){hash_set<const char*, hash<const char*>, eqstr>::const_iterator it= Set.find(word);std::cout << " " << word << ": "<< (it != Set.end() ? "present" : "not present") << std::endl;}

int main(){hash_set<const char*, hash<const char*>, eqstr> Set;Set.insert("kiwi");Set.insert("plum");Set.insert("apple");Set.insert("mango");Set.insert("apricot");Set.insert("banana");

loopup(Set, "mango");   //mango: presentloopup(Set, "apple");   //apple: presentloopup(Set, "durian");  //durian: not present

//ite1类型为hash_set<const char*, hash<const char*>, eqstr>::iteratorauto iter = Set.begin();for (; iter != Set.end(); ++iter)std::cout << *iter << ""; //banana plum mango apple kiwi apricotstd::cout << std::endl;return 0;}
  • 下面演示在hash_set中存储int整型

int main(){hash_set<int> Set; //hash_set默认缺省为100。SGI内部采用质数193Set.insert(3);  //实际大小为193Set.insert(196);Set.insert(1);Set.insert(389);Set.insert(194);Set.insert(387);

//ite1类型为hash_set<const char*, hash<const char*>, eqstr>::iteratorauto iter = Set.begin();for (; iter != Set.end(); ++iter)std::cout << *iter << ""; //387 194 1 389 196 3std::cout << std::endl;return 0;}
  • 此时底层的hashtable构造如下:

二、hash_map

  •  由于hash_map底层是以hash table实现的,因此hash_map只是简单的调用hash table的方法即可

  • 与map的异同点:

    • hash_map与map都是用来快速查找元素的

    • 但是map会对元素自动排序,而hash_map没有

    • hash_map和map的使用方法相同

  • 在介绍hash table的hash functions的时候说过,hash table有一些无法处理的类型(除非用户自己书写hash function)。因此hash_map也无法自己处理

hash_map源码

//以下代码摘录于stl_hash_map.h//以下的hash<>是个function object,定义于<stl_hash_fun.h>中//例如:hash<int>::operator()(int x)const{return x;}template <class _Key, class _Tp, class _HashFcn, class _EqualKey,class _Alloc>class hash_map{// requirements:

__STL_CLASS_REQUIRES(_Key, _Assignable);__STL_CLASS_REQUIRES(_Tp, _Assignable);__STL_CLASS_UNARY_FUNCTION_CHECK(_HashFcn, size_t, _Key);__STL_CLASS_BINARY_FUNCTION_CHECK(_EqualKey, bool, _Key, _Key);

private://以下使用的select1st<>定义在<stl_function.h>中typedef hashtable<pair<const _Key,_Tp>,_Key,_HashFcn,_Select1st<pair<const _Key,_Tp> >,_EqualKey,_Alloc> _Ht;_Ht _M_ht;

public:typedef typename _Ht::key_type key_type;typedef _Tp data_type;typedef _Tp mapped_type;typedef typename _Ht::value_type value_type;typedef typename _Ht::hasher hasher;typedef typename _Ht::key_equal key_equal;

typedef typename _Ht::size_type size_type;typedef typename _Ht::difference_type difference_type;typedef typename _Ht::pointer pointer;typedef typename _Ht::const_pointer const_pointer;typedef typename _Ht::reference reference;typedef typename _Ht::const_reference const_reference;

typedef typename _Ht::iterator iterator;typedef typename _Ht::const_iterator const_iterator;

typedef typename _Ht::allocator_type allocator_type;

hasher hash_funct() const { return _M_ht.hash_funct(); }key_equal key_eq() const { return _M_ht.key_eq(); }allocator_type get_allocator() const { return _M_ht.get_allocator(); }

public://缺省使用大小为100的表格,将被hash table调整为最接近且较大的质数hash_map() : _M_ht(100, hasher(), key_equal(), allocator_type()) {}explicit hash_map(size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()) {}hash_map(size_type __n, const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()) {}hash_map(size_type __n, const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a) {}

#ifdef __STL_MEMBER_TEMPLATEStemplate <class _InputIterator>hash_map(_InputIterator __f, _InputIterator __l): _M_ht(100, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }template <class _InputIterator>hash_map(_InputIterator __f, _InputIterator __l, size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }template <class _InputIterator>hash_map(_InputIterator __f, _InputIterator __l, size_type __n,const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }template <class _InputIterator>hash_map(_InputIterator __f, _InputIterator __l, size_type __n,const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a){ _M_ht.insert_unique(__f, __l); }

#elsehash_map(const value_type* __f, const value_type* __l): _M_ht(100, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_map(const value_type* __f, const value_type* __l, size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_map(const value_type* __f, const value_type* __l, size_type __n,const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_map(const value_type* __f, const value_type* __l, size_type __n,const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a){ _M_ht.insert_unique(__f, __l); }

hash_map(const_iterator __f, const_iterator __l): _M_ht(100, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_map(const_iterator __f, const_iterator __l, size_type __n): _M_ht(__n, hasher(), key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_map(const_iterator __f, const_iterator __l, size_type __n,const hasher& __hf): _M_ht(__n, __hf, key_equal(), allocator_type()){ _M_ht.insert_unique(__f, __l); }hash_map(const_iterator __f, const_iterator __l, size_type __n,const hasher& __hf, const key_equal& __eql,const allocator_type& __a = allocator_type()): _M_ht(__n, __hf, __eql, __a){ _M_ht.insert_unique(__f, __l); }#endif /*__STL_MEMBER_TEMPLATES */

public://所有操作几乎都有hash table的对应版本。传递调用即可size_type size() const { return _M_ht.size(); }size_type max_size() const { return _M_ht.max_size(); }bool empty() const { return _M_ht.empty(); }void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); }

#ifdef __STL_MEMBER_TEMPLATEStemplate <class _K1, class _T1, class _HF, class _EqK, class _Al>friend bool operator== (const hash_map<_K1, _T1, _HF, _EqK, _Al>&,const hash_map<_K1, _T1, _HF, _EqK, _Al>&);#else /* __STL_MEMBER_TEMPLATES */friend bool __STD_QUALIFIERoperator== __STL_NULL_TMPL_ARGS (const hash_map&, const hash_map&);#endif /* __STL_MEMBER_TEMPLATES */



iterator begin() { return _M_ht.begin(); }iterator end() { return _M_ht.end(); }const_iterator begin() const { return _M_ht.begin(); }const_iterator end() const { return _M_ht.end(); }

public:pair<iterator,bool> insert(const value_type& __obj){ return _M_ht.insert_unique(__obj); }#ifdef __STL_MEMBER_TEMPLATEStemplate <class _InputIterator>void insert(_InputIterator __f, _InputIterator __l){ _M_ht.insert_unique(__f,__l); }#elsevoid insert(const value_type* __f, const value_type* __l) {_M_ht.insert_unique(__f,__l);}void insert(const_iterator __f, const_iterator __l){ _M_ht.insert_unique(__f, __l); }#endif /*__STL_MEMBER_TEMPLATES */pair<iterator,bool> insert_noresize(const value_type& __obj){ return _M_ht.insert_unique_noresize(__obj); }

iterator find(const key_type& __key) { return _M_ht.find(__key); }const_iterator find(const key_type& __key) const{ return _M_ht.find(__key); }

_Tp& operator[](const key_type& __key) {return _M_ht.find_or_insert(value_type(__key, _Tp())).second;}

size_type count(const key_type& __key) const { return _M_ht.count(__key); }

pair<iterator, iterator> equal_range(const key_type& __key){ return _M_ht.equal_range(__key); }pair<const_iterator, const_iterator>equal_range(const key_type& __key) const{ return _M_ht.equal_range(__key); }

size_type erase(const key_type& __key) {return _M_ht.erase(__key); }void erase(iterator __it) { _M_ht.erase(__it); }void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); }void clear() { _M_ht.clear(); }

void resize(size_type __hint) { _M_ht.resize(__hint); }size_type bucket_count() const { return _M_ht.bucket_count(); }size_type max_bucket_count() const { return _M_ht.max_bucket_count(); }size_type elems_in_bucket(size_type __n) const{ return _M_ht.elems_in_bucket(__n); }};

template <class _Key, class _Tp, class _HashFcn, class _EqlKey, class _Alloc>inline booloperator==(const hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm1,const hash_map<_Key,_Tp,_HashFcn,_EqlKey,_Alloc>& __hm2){return __hm1._M_ht == __hm2._M_ht;}

hash_map使用演示案例

#include <iostream>#include <hash_map>#include <string.h>using namespace std;

struct eqstr{bool operator()(const char* s1, const char* s2){return strcmp(s1, s2) == 0;}};

int main(){hash_map<const char*, int,hash<const char*>, eqstr> days;days["january"] = 31;days["february"] = 28;days["march"] = 31;days["april"] = 30;days["may"] = 31;days["june"] = 30;days["july"] = 31;days["august"] = 31;days["september"] = 30;days["october"] = 31;days["november"] = 30;days["december"] = 31;



std::cout << "september ->" << days["september"] << std::endl;//30std::cout << "june ->" << days["june"] << std::endl;          //30std::cout << "february ->" << days["february"] << std::endl;  //28std::cout << "december ->" << days["december"] << std::endl;  //31



//ite1类型为hash_map<const char*, int,hash<const char*>, eqstr>::iteratorauto iter = days.begin();for (; iter != days.end(); ++iter)std::cout << iter->first << "";//september june july may january february december//march april november october auguststd::cout << std::endl;return 0;}

三、hash_multiset

  • hash_multiset与hash_set使用起来相同,只是hash_multiset中允许键值重复

  • 在源码中,hash_multiset调用的是insert_equal(),而hash_set调用的是insert_unique()

四、hash_multimap

  • hash_multimap与hash_map使用起来相同,只是hash_multimap中允许键值重复

  • 在源码中,hash_multimap调用的是insert_equal(),而hash_map调用的是insert_unique()

相关推荐
实付 39.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值