hash表有两点要考虑:
1,寻址:定义hash函数,即对key做运算的一个函数,返回对应的key+value的存放位置。这一点要求定义一个hash函数
2,解决冲突:判断两个key是否相等,对两个key通过函数计算得到同一个hash地址时,需要这样的判断。这一点要求重载==运算符
SGI STL中hash_map的声明:
template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
class _EqualKey = equal_to<_Key>,
class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class hash_map
{
...
}
hash_map的声明中第三个参数就是hash函数,缺省为hash<_Key>,其源码如下:
template <class _Key> struct hash { };
在SGI STL中,提供了以下hash函数:(每个前面都有template <>)
struct hash<char*>
struct hash<const char*>
struct hash<char>
struct hash<unsigned char>
struct hash<signed char>
struct hash<short>
struct hash<unsigned short>
struct hash<int>
struct hash<unsigned int>
struct hash<long>
struct hash<unsigned long>
如果你的key使用的是以上类型中的一种,那么就可以使用缺省的hash函数。
在没有指定hash函数和比较函数的时候,系统会根据key的类型提供缺省的,如:
hash_map<int, string> stHashMap; 即等同于 hash_map<int, string, hash<int>, equal_to<int> > stHashMap;
hash<int>是个函数对象,它的实现如下:
struct hash<int>
{
size_t operator()(int __x) const { return __x; }
};
struct str_hash
{
size_t operator ()(const string& str) const
{
unsigned long __h = 0;
for (size_t i = 0 ; i < str.size() ; i ++)
__h = 5*__h + str[i];
return size_t(__h);
}
};
如果你希望利用系统定义的字符串hash函数,你可以这样写:
struct str_hash
{
size_t operator ()(const string& str) const
{
return __stl_hash_string(str.c_str());
}
};
有了str_hash,就可以定义string类型key的hash map了:
hash_map<string, string, str_hash> stNameHashMap;
在自定义hash函数时要注意以下几点:
1,使用struct,然后重载operator()
2,返回是size_t
3,参数是你要hash的key的类型
4,函数是const类型的
另一种自定义hash函数的方法是特化系统的hash模板,如下的示例代码。
hash_map的声明中第四个参数就是比较函数,缺省为equal_to<_Key>,其源码如下:
template<class _Arg1, class _Arg2, class _Result>
struct binary_function
{
typedef _Arg1 first_argument_type;
typedef _Arg2 second_argument_type;
typedef _Result result_type;
};
template<class _Tp>
struct equal_to : public binary_function<_Tp,_Tp,bool>
{
bool operator ()(const _Tp& __x, const _Tp& __y) const { return __x == __y; }
};
如果你使用一个自定义的数据类型,如struct TSomeStruct, 可以通过重载==运算符:
struct TSomeStruct
{
int m_i32ID;
int m_i32Len;
bool operator ==(const TSomeStruct & other) const
{
return (m_i32ID == other.m_i32ID) && (m_i32Len == other.m_i32Len) ;
}
};
这样就可以使用equal_to<TSomeStruct>作为比较函数了。
另一种方法就是使用函数对象,自定义一个比较函数体:
struct compare_str
{
bool operator ()(const char* psz1, const char* psz2) const
{
return (0 == strcmp(psz1, psz2));
}
};
有了compare_str,就可以使用hash_map了:
typedef hash_map<const char*, string, hash<const char*>, compare_str> StrIntHashMap;
示例:
class CTimerKey
{
private:
ITimerSink* m_poSink;
int m_i32EventID;
public:
void Set(ITimerSink* poSink, int i32EventID)
{
m_poSink = poSink;
m_i32EventID = i32EventID;
}
bool operator ==(const CTimerKey& other) const
{
return (m_poSink == other.m_poSink) && (m_i32EventID == other.m_i32EventID);
}
inline size_t Hash() const
{
return (size_t) m_poSink;
}
void OnTimer()
{
if (m_poSink)
{
m_poSink->OnTimer(m_i32EventID);
}
}
};
// 模板特化方式自定义hash函数
namespace std
{
template<>
struct hash<CTimerKey>
{
size_t operator ()(const CTimerKey& o) const
{
return o.Hash();
}
};
}