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 );
相關文章
相關標籤/搜索