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

);

 

    原文作者:_pop
    原文地址: https://www.cnblogs.com/pop-lar/p/4714281.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞