VC散列表

vc下有2个版本的散列表类,hash_map和unordered_map,hash_map位于stdext命名空间,unordered_map在std命名空间(vs2008及其之后的版本可用),官方推荐使用unordered_map,前者是一个旧的非标版本。

 2者使用起来很类似,但构造函数有明显不同。 在使用int之类的值类型作为key的情况下,后几个参数可以使用默认值,无需提供hash function和compare function。但如果需要特殊类型作为散列键值的情况用起来就麻烦很多,比如用字符串string作为散列键值(但如果include了<string>也是无需提供hash function和compare function,很方便)。

template<
    class
 Key,
     class Ty,
     class Hash = std::hash<Key>,
     class Pred = std::equal_to<Key>,
     class Alloc = std::allocator<std::pair< const Key, Ty> > >
     class unordered_map;

template <
    class Key, 
    class Type, 
    class Traits=hash_compare<Key, less<Key> >, 
    class Allocator=allocator<pair < const Key, Type> > >
    class hash_map;  

 

散列表类有几个概念搞清楚后才能很好的理解这2个构造函数。key键值、value实值、hash值是哈希表最基本的概念,在存储value值的时候,散列表需要将key值转换为hash值(hash值会被用来当做数组下标使用),其类型为无符号整形。key值 --> hash值的映射函数就是hash函数,vc为一些类型的key提供了默认的hash函数,比如int和string。映射函数并不保证key与hash值的映射关系是一一对应的,可能出现多个key值映射到一个hash值的情况。此时我们需要比较函数来解决冲突,用来区分相同hash值下的不同key值。

回到上面的2个构造函数,unordered_map是比较容易理解的,第三个入参【class Hash = std::hash<Key>】,它所需要的类型其实是个函数对象,用来完成散列映射。默认使用了名为hash的函数对象。第四个参数【class Pred = std::equal_to<Key>】,所需要的类型也是函数对象,用来完成hash值冲突后的key值的比较。对这2个参数我们也可以使用自定义的函数对象,比如下面(假设key的类型为int)。另外,string类型比较特殊,后面另说。

struct hashMy
{
    size_t  operator()( int _Val)  const{ return _Val% 100;}
}; 

struct equalMy
{    // functor for operator==
    bool operator()(const int _Left, const int _Right) const
    {    // apply operator== to operands
        return (_Left == _Right);
    }
};

 

std::unordered_map<int,int,hashMy,equalMy> s3; 

 

 而hash_map类的构造函数则是由第三个入参完成hash函数和比较函数2个功能。其默认的函数对象的定义如下

template< class Key,  class Traits = less<Key> >
    class hash_compare
   {
   Traits comp;
public:
    const size_t bucket_size =  4;
    const size_t min_buckets =  8;
   hash_compare( );
   hash_compare( Traits pred );
   size_t  operator( )(  const Key& _Key )  const;
    bool  operator( )( 
       const Key& _Key1,
       const Key& _Key2
   )  const;
   };

注意这个类没有使用equal_to来做hash值冲突后的key值的比较,而是默认使用less函数。据说这是为了提高冲突后的查找效率,当需要判断等于的时候通过!(a < b) && !(b < a)来实现.....自定义的方式如下,假设key是int型。

class hash_compare_my
{
public:
     enum
    { 
        bucket_size =  4,
        min_buckets =  8
    };
   
    size_t  operator( )(  const  int& _Key )  const{ return _Key% 100;}
     bool  operator( )(  const  int& _Key1, const  int& _Key2 )  const
    {
         return (_Key1 < _Key2);
    }
};

 

stdext::hash_map<int,int,hash_compare_my> t; 

 

 

平时经常需要用到string作为key的情况,在不include<string>的情况下,unordered_map会编译失败,我们需要提供自定义的string比较函数,string的hash函数可以复用库中提供的string hash函数。

注意,有include<string> 的情况下不需要提供自定义的hash函数和比较函数。

struct equal_s
{
     bool  operator()( const std:: string& s1, const std:: string& s2) const
    {
         return s1.compare(s2) ==  0;
    }
};
struct less_s  
{  
     bool  operator ()( const std:: string & str1,  const std:: string & str2)  const  
    {  
         return str1.compare(str2) <  0;  
    }  
}; 
std::unordered_map<std:: string, int,std::hash<std:: string>,equal_s> s;
stdext::hash_map<std:: string, int,stdext::hash_compare<std:: string,less_s> > s1;

 

最后,散列表的插入函数insert有多个重载版本,如果遇到插入的key已经存在则插入操作失败,注意批量插入的重载版本不会显式提示失败。

template< class InputIterator>
     void insert(
        InputIterator _First,
        InputIterator _Last
);

pair <iterator,  bool> insert(
     const value_type& _Val
);

 

转载于:https://www.cnblogs.com/pop-lar/p/4714281.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值