hash_map

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; }
};


当然也可以定义自己的hash函数。对于自定义变量,就必须自定义hash函数。例如string类型:

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();
        }
    };
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值