unordered_map源码解析和个人理解

参考链接 https://blog.csdn.net/ddkxddkx/article/details/6555754

还有这个源码解析https://zrj.me/archives/1248

1.下面的代码结果是多少?

#include <unordered_map>
#include <cstring>
#include <iostream>
using namespace std;
class A  // 自定义类型必须手写比较函数
{
public:
    A(): val(0) {}
    int get_val() const {return val;}
    bool operator== (const A& b) const {return val == b.get_val();}
private:
    int val;
};

struct A_hash // 自定义类型必须手写哈希函数
{
    size_t operator() (const A& s) const
    {
        // return __stl_hash_string(s.c_str());
        return s.get_val()%10;
    }
};

int main()
{
    A a;
    unordered_map<A, int, A_hash, equal_to<A> > m;
    m[a] = 1;
    A b;
    m[b] = 2;
    cout << m[a] << endl;
    return 0;
}

答案:2

为什么是2呢?

这要从unordered_map的原型来看

  template<class _Key, class _Tp,
           class _Hash = hash<_Key>,
           class _Pred = std::equal_to<_Key>,
           class _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
    class unordered_map

unordered_map<string, int>

相当于

unordered_map<string, int, hash<int>, equal_to<int>, allocator<pair<const string, int>>>

1.哈希函数

struct hash<int> {
        size_t operator()(int __x) const { return __x; }
};

如果是自定义类型,要自己实现哈希函数

2.比较函数

比较函数用于当哈希值对应的位置已经有值的时候,进行比较

3.显式具体化

hashtable.h

/// Base types for unordered_map.
  template<bool _Cache>
    using __umap_traits = __detail::_Hashtable_traits<_Cache, false, true>;


  template<typename _Key,
           typename _Tp,
           typename _Hash = hash<_Key>,
           typename _Pred = std::equal_to<_Key>,
           typename _Alloc = std::allocator<std::pair<const _Key, _Tp> >,
           typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>>
    using __umap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>,
                                        _Alloc, __detail::_Select1st,
                                        _Pred, _Hash,
                                        __detail::_Mod_range_hashing,
                                        __detail::_Default_ranged_hash,
                                        __detail::_Prime_rehash_policy, _Tr>;



// _Key std::pair<const _Keym _Tp>
typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc>  _Hashtable;
_Hashtable _M_h;


explicit
unordered_map(size_type __n,
              const hasher& __hf = hasher(),
              const key_equal& __eql = key_equal(),
              const allocator_type& __a = allocator_type())
: _M_h(__n, __hf, __eql, __a)
{}

__umap_hashtable:

		template<bool _Cache_hash_code, bool _Constant_iterators, bool _Unique_keys>
		struct _Hashtable_traits
		{
			using __hash_cached = __bool_constant<_Cache_hash_code>;
			using __constant_iterators = __bool_constant<_Constant_iterators>;
			using __unique_keys = __bool_constant<_Unique_keys>;
		};

_HashTable

下面是__cache_default

template<typename _Tp, typename _Hash>
    using __cache_default
      =  __not_<__and_<// Do not cache for fast hasher.
                       __is_fast_hash<_Hash>,
                       // Mandatory to have erase not throwing.
                       __detail::__is_noexcept_hash<_Tp, _Hash>>>;

 

  template<typename _Key, typename _Value, typename _Alloc,
           typename _ExtractKey, typename _Equal,
           typename _H1, typename _H2, typename _Hash,
           typename _RehashPolicy, typename _Traits>
    class _Hashtable
    : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
                                       _H1, _H2, _Hash, _Traits>,
      public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
                                 _H1, _H2, _Hash, _RehashPolicy, _Traits>,
      public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal,
                               _H1, _H2, _Hash, _RehashPolicy, _Traits>,
      public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
                                    _H1, _H2, _Hash, _RehashPolicy, _Traits>,
      public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
                                 _H1, _H2, _Hash, _RehashPolicy, _Traits>,

默认的哈希函数

      __hash_code
      _M_hash_code(const _Key& __k) const
      {
              // code2
              // std::cout << "code2" << std::endl;
              return _M_h1()(__k); }

_M_h1():

      const _H1&
      _M_h1() const { std::cout << "const_M_h1" << std::endl; return __ebo_h1::_S_cget(*this); }

__ebo_h1::_S_cget(*this):

      using __ebo_h1 = _Hashtable_ebo_helper<1, _H1>;
      using __ebo_h2 = _Hashtable_ebo_helper<2, _H2>;
  template<int _Nm, typename _Tp>
    struct _Hashtable_ebo_helper<_Nm, _Tp, true>
    : private _Tp
    {
      _Hashtable_ebo_helper() = default;

      template<typename _OtherTp>
        _Hashtable_ebo_helper(_OtherTp&& __tp)
          : _Tp(std::forward<_OtherTp>(__tp))
        { }

      static const _Tp&
      _S_cget(const _Hashtable_ebo_helper& __eboh)
      { return static_cast<const _Tp&>(__eboh); }

      static _Tp&
      _S_get(_Hashtable_ebo_helper& __eboh)
      { return static_cast<_Tp&>(__eboh); }
    };

返回一个H1,H1是什么?第六个参数


  template<typename _Key,
           typename _Tp,
           typename _Hash = hash<_Key>,
           typename _Pred = std::equal_to<_Key>,
           typename _Alloc = std::allocator<std::pair<const _Key, _Tp> >,
           typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>>
    using __umap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>,
                                        _Alloc, __detail::_Select1st,
                                        _Pred, _Hash, // 这是第六个参数
                                        __detail::_Mod_range_hashing, // _M_bucket_index
                                        __detail::_Default_ranged_hash,
                                        __detail::_Prime_rehash_policy, _Tr>;

就是用默认的哈希函数来计算键值

所以,对自定义类型,需要自己实现哈希函数与比较函数

插入:

      operator[](const key_type& __k)
      { return _M_h[__k]; }

hashtable_policy.h

using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
                                     _Equal, _H1, _H2, _Hash,
                                     _RehashPolicy, _Traits>;


  template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
           typename _H1, typename _H2, typename _Hash,
           typename _RehashPolicy, typename _Traits>
    auto
    _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
              _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::
    operator[](const key_type& __k)
    -> mapped_type&
    {
      __hashtable* __h = static_cast<__hashtable*>(this); // 这个只能在子类方法中使用
      __hash_code __code = __h->_M_hash_code(__k); // 计算哈希值
      std::size_t __n = __h->_M_bucket_index(__k, __code);
      __node_type* __p = __h->_M_find_node(__n, __k, __code);

      if (!__p)
        {
          __p = __h->_M_allocate_node(std::piecewise_construct,
                                      std::tuple<const key_type&>(__k),
                                      std::tuple<>());
          return __h->_M_insert_unique_node(__n, __code, __p)->second;
        }

      return __p->_M_v().second;
    }

下面来看一看_M_bucket_index

      std::size_t
      _M_bucket_index(const _Key&, __hash_code __c, std::size_t __n) const
      {
              //std::cout << "bucket2" << std::endl;
              return _M_h2()(__c, __n); }

看一看_M_h2:

      const _H2&
      _M_h2() const { return __ebo_h2::_S_cget(*this); }

      _H2&
      _M_h2() { return __ebo_h2::_S_get(*this); }

返回了 H2

		struct _Mod_range_hashing
		{
			typedef std::size_t first_argument_type;
			typedef std::size_t second_argument_type;
			typedef std::size_t result_type;

			result_type
				operator()(first_argument_type __num,
					second_argument_type __den) const noexcept
			{
				return __num % __den;
			}
		};

 

 

如果两个key相等的时候,不用插入

不相等,则在桶里面插入

查找:

两个key相等放回

不相等找下一个

函数原型

template <class _Tp>
struct equal_to : public binary_function<_Tp,_Tp,bool>
{
        bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值