STL源码剖析——hashtable, unordered_set, unordered_map

HashTable

解决碰撞的方式:

1.线性探测

负载系数 = 元素数量 / 桶数量

如果某个位置空间不可用,则循序往下(尾端回到头部)查找可用空间

惰性删除:只标记删除记号,实际删除待表格重新整理时再进行

2.二次探测

如果H位置被占用,则依序尝试H+1, H+4, H+9, …

3.开链separate chaining:每个桶维护一个list

节点:

template <class Value>
struct __hashtable_node
{
    __hashtable_node *next;
    Value val;
};

迭代器

forward_iterator

template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
struct __hashtable_iterator {
    node *cur; //所指的节点
    hashtable *ht;  //指向容器

    iterator& operator++() {
        //如果不是list尾部,直接返回
        const node* old = cur;
        cur = cur->next;
        //如果不是list尾部,直接返回
        if (!cur) {
            //否则返回下一个不为空的list头部
            size_type bucket = ht->bkt_num(old->val);
            while (!cur && ++bucket < ht->buckets.size())
                cur = ht->buckets[bucket];
            }
        }
        return *this;
    }

    //没有--操作
};

hashtable数据结构

//EqualKey:判断键值是否相同的方法
template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc = alloc>
class hashtable {
private:
    vector<node*, Alloc> buckets; //存放桶
    size_type num_elements;
public:
    size_type bucket_count();
};

选择质数个桶,当元素个数>篮子个数,进行rehash,选择篮子个数*2附近的质数

 

空间配置

node *new_node(const value_type &obj);

void delete_node(node *n);

//构造函数调用initialize_buckets
void initialize_buckets(size_type n)
{
    //寻找合适的桶数量
    //返回最接近n并大于n的质数
    const size_type n_buckets = next_size(n);
    buckets.reserve(n_buckets);
    buckets.insert(buckets.end(), n_buckets, (node*)0);
    num_elements = 0;
}

插入
pair<iterator, bool> insert_unique(const value_type& obj); //不允许插入重复
iterator insert_equal(const value_type &obj); //允许插入重复


void resize(size_type num_elements_hint)
{
    const size_type old_n = buckets.size();
    if (num_elements_hint > old_n) {
        const size_type n = next_size(num_elements_hint);
        if (n > old_n) {
            //创建新的bucket vector
            vector<node *, A> tmp(n, (node*) 0);
            //将原来的数据拷贝到新的bucket vector中
            __STL_TRY {
                for (size_type bucket = 0; bucket < old_n; ++bucket) {
                    node *first = buckets[bucket];
                    while (first) {
                        size_type new_bucket = bkt_num(first->val, n);
                        //每次都插入到list头部
                        buckets[bucket] = first->next;
                        first->next = tmp[new_bucket];
                        tmp[new_bucket] = first;
                        first = buckets[bucket];
                }
            }
            buckets.swap(tmp);
        }
    }
}

获取桶序号的方式:取余

size_type bkt_num_key(const key_type &key, size_t n) const 
{
    return hash(key) % n;
}

hash-function

对于数值类型(char, (unsigned)short, (unsigned)int, (unsigned)long),直接返回其值(转型为size_t)

如:

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

对于char*:

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

unordered_set/unordered_multiset

底层机制以hash table完成

unordered_set采用insert_unique进行插入,unordered_multiset采用insert_equal完成

 

unordered_map/unordered_multimap

底层机制以hash table完成

unordered_map采用insert_unique进行插入,unordered_multimap采用insert_equal完成

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值