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,很方便)。
app

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值。
less

回到上面的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);
    }
};spa

 

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

 

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

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函数。blog

注意,有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已经存在则插入操做失败,注意批量插入的重载版本不会显式提示失败。
string

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

pair <iterator,  bool> insert(
     const value_type& _Val );
相关文章
相关标签/搜索