STL(七)——hashtable(二):哈希函数

介绍STL里hashtable的使用

例子:

#include<hash_set>
#include<iostream>
using namespace std;

int main()
{
    hashtable<
        int,           //Value类型
        hash<int>,     //键值类型
        identity<int>, //提取键值的方法
        equal_to<int>, //判断相等的方法
        alloc>         //分配内存
        iht(50, hash<int>(), equal_to<int>()); //声明iht变量并调用hashtable构造函数
        
        iht.insert_unique(59);
        iht.insert_unique(63);
        
    //声明一个迭代器
    hashtable<
        int,  /
        int,
        hash<int>,
        identity<int>,
        equal_to<int>,
        alloc>
        ::iterator ite = iht.begin(); //hash table的迭代器是前向迭代器
        
        for(int i = 0; i < iht.size(); ++i, ++ite)
        {
            cout<<*ite<<' ';
        }
}

hash table的find函数和count函数:

iterator find(const key_type& key)
{
    size_type n = bkt_num(key);
    node* first;
    //以下,从bucket list从头开始对比,对比相同就返回
    for (first = buckets[n];
        first && !equals(get_key(first->val), key);
        first = first->next)
    {}
    return iterator(first, this);
}

size_type count(const key_type& key) const
{
    const size_type n = bkt_num_key(key);
    size_type result = 0;
    //以下,从bucket list的头开始,一一对比每个元素的键值。对比成功就+1
    for(const node* cur = buckets[n]; cur; cur = cur->next)
    {
        if(equals(get_key(cur->val),key))
        {
            ++result;
        }
    }
    return result;
}

hash function

<stl_hash_fun.h>定义有数个现成的hash function,全都是仿函数。先前谈到hash function是用来计算元素位置的。针对char,int,long这些类型,hash function什么也没做,只是返回了原值。但对于字符串const char*,就设计了如下转换函数:

template<class key> struct hash{};

inline size_t __stl_hash_string(const char* s)
{
    unsigned long h = 0;
    for(;*s;++s)
        h = 5*h + *s;
    return size_t(h);
}

//特化 STL的hash function还是挺简单的,直接返回值,仅仅处理了类型,返回一个可mod的值
//STL无法处理上述列出的各类型意外的元素,例如string,double等等,用户需要自定义自己的hashfunction
_stl_template_null struct hash<char*> 
{ size_t operator()(const char* s) const { return _stl_hash_string(s);}};//重载了()

_stl_template_null struct hash<const char*>
{ size_t operator()(const char* s){ return _stl_hash_string(s);}};

_stl_template_null struct hash<char>
{ size_t operator()(char x) const {return x}};

_stl_template_null struct hash<unsigned char>
{ size_t operator()(unsigned int) const{return x;}};

_stl_template_null struct hash<signed char>
{ size_t operator()(unsigned char)const {return x;}}

..........

上面代码表明,STL无法处理上述所列各项形别以外的元素,例如string,double等等。欲处理这些,用户必须自定义自己的hash function。

hash_set

虽然STL只规范复杂度和接口,并不规范实现方法,但STL set多以RB-tree为底层机制。SGI则是在STL标志规格之外又提供了一个所谓的hash_set,以hashtable为底层机制。由于hash_set所提供的操作接口,hashtable都提供了,所以几乎所有hash_set的操作行为,都只是转调了hashtable的操作行为而已。下面是hash_set的代码摘录:

template<
    class Value,
    class HashFunc = hash<Value>,
    class EqualKey = equal_to<Value>,
    class Alloc = alloc>
class hash_set
{
private:
    typedef hashtable<Value, Value, HashFunc, identity<Value>, EqualKey, Alloc> ht;
    ht rep; //底层是以hash table 完成
public:
    typedef typename ht::key_type key_type; //typename是告知编译器这是类型不是static变量
    typedef typename ht::value_type value_type;
    typedef typename ht::hasher hasher;
    typedef typename ht::key_equal key_equal;
    typedef typename ht::size_type size_type;
    typedef typename ht::difference_type difference_type;
    typedef typename ht::const_pointer pointer;
    typedef typename ht::const_pointer const_pointer;
    typedef typename ht::const_reference reference;
    typedef typename ht::const_reference const_reference;
    typedef typename ht::const_iterator iterator;
    typedef typename ht::const_iterator const_iterator;
    hasher hash_funct() const{ return rep.hash_funct();}
    key_equal key_eq() const {return rep.key_eq();}
    
public:
    hash_set():rep(100, hasher(), key_equal()){}
    explict hash_set(size_type n): rep(n, hasher(), key_equal()){}
    hash_set(size_type n, const hasher& hf):rep(n, hf, key_equal()){}
    hash_set(size_type n, const hasher& hf, const key_equal& eql):rep(n, hf, eql){}

template<class InputIteratir>
hash_set(InputIterator f, InputIterator l):rep(100, hasher(), key_equal())
    { rep.insert_unique(f,l);}

template<class InputIterator>
hash_set(InpurIterator f, InputIterator l, size_type n):rep(n, hasher(),key_equal())
    { rep.insert_unique(f,l);}
.......//省略成吨的构造函数

public:
size_type size() const{ return rep.size();}
size_type max_size() const { return rep.max_size();}
bool empty() const { return rep.empty();}
void swap(hash_set& hs) { rep.swap(hs.rep);}
friend bool operator== __STL_NULL_TMPL_ARGS(const hash_set&, const hash_set&);
iterator begin() const { return rep.begin();}
iterator end() const {return rep.end();}

.....//省略成吨的接口函数



};    

总结:

如上便是SGI STL实现hash table以及对接STL标准的代码和一些注释,还是一如既往的朴素而高效。

猜你喜欢

转载自blog.csdn.net/Pokemon_Master/article/details/82591392