使用C++模板手撸简易hash_map

使用了c++自带的hash模板类
使用 std::list 作为链表解决冲突
为了省事懒得写迭代器,所有桶全部使用一条链了

#ifndef _MY_HASH_MAP_H_
#define _MY_HASH_MAP_H_
#include
#include
#include


template, typename keyeq_t = std::equal_to>
class my_hash_map {
    using pair_t = std::pair;
    using container_t = std::list>;
    using iterator = typename container_t::iterator;
    using const_iterator = typename container_t::const_iterator;

    container_t elem_list;
    vector it_vec;
    size_t collision;

    static const hash_t hash;
    static const keyeq_t eq;

    size_t index(const key_t& key) const { return hash(key) % it_vec.size(); }

    bool empty_buket(size_t buket_id)const { return it_vec[buket_id] == elem_list.end(); }
    size_t buket_cnt() const { return it_vec.size(); }

    void rehash(size_t buket_cnt) {
        typename remove_reference::type new_map(buket_cnt);
        for (auto& p : elem_list) new_map.insert(std::move(p),false);
        *this = std::move(new_map);
    }

    iterator find(const key_t& key) {
        size_t id = index(key);
        iterator end_it = elem_list.end(), now_it = it_vec[id];
        while (now_it != end_it && index(now_it->first) == id) {
            if (eq(key, now_it->second)) return now_it;
            ++now_it;
        }
        return end_it;
    }

    const_iterator find(const key_t& key)const {
        size_t id = index(key);
        const_iterator end_it = elem_list.end(), now_it = it_vec[id];
        while (now_it != end_it && index(now_it->first) == id) {
            if (eq(key, now_it->second)) return now_it;
            ++now_it;
        }
        return end_it;
    }

    void check_rehash() {
        double collision_rate = (double)collision / size();
        if (collision_rate <= 1.0 / 16 && buket_cnt() > 32) rehash(buket_cnt() / 2);
        else if (collision_rate >= 1.0/2) rehash(buket_cnt() * 2);
    }

public:

    my_hash_map(size_t buket_cnt) :elem_list(), it_vec(buket_cnt, elem_list.end()), collision(0) {}
    my_hash_map() :my_hash_map(32) {}

    iterator begin() { return elem_list.begin(); }
    iterator end() { return elem_list.end(); }

    size_t count(const key_t& key)const  {
        size_t id = index(key);
        return elem_list.end() != find(key);
    }

    size_t size() const { return elem_list.size(); }

    void insert(const pair_t& p,bool check = true) {
        static int loop = 0;
        if (count(p.first)) return;
        size_t id = index(p.first);
        iterator &it = it_vec[id];
        if (!empty_buket(id)) collision++;
        it = elem_list.insert(it, p);
        if (check && (loop = (loop+1)%10) && (double)collision / it_vec.size() > 1.0 / 2)
            rehash(it_vec.size()*2);
    }

    void erase(const key_t& key) {
        static int loop = 0;
        iterator it = find(key);
        if (it == elem_list.end()) return;
        iterator& beg_it = it_vec[index(key)];
        if (beg_it == it) {
            iterator next_it = std::next(it);
            if (next_it == elem_list.end() || index(it->first) != index(std::next(it)->first)) {
                elem_list.erase(it);
                beg_it = elem_list.end();
            }
            else {
                beg_it = elem_list.erase(it);
                collision--;
            }
        }
        else {
            elem_list.erase(it);
            collision--;
        }
        if ((loop = (loop + 1) % 10) && it_vec.size() > 32 && (double)collision / it_vec.size() < 1.0 / 8)
            rehash(it_vec.size() / 2);
    }

    val_t& operator[](const key_t& key) { 
        iterator it = find(key);
        if (it==elem_list.end()) insert(pair_t{ key,val_t() });
        return it->second; 
    }

};

template
const hash_t my_hash_map::hash;

template
const keyeq_t my_hash_map::eq;

#endif //_MY_HASH_MAP_H_

你可能感兴趣的:(使用C++模板手撸简易hash_map)