使用了c++自带的hash模板类
使用 std::list 作为链表解决冲突
为了省事懒得写迭代器,所有桶全部使用一条链了
#ifndef _MY_HASH_MAP_H_
#define _MY_HASH_MAP_H_
#include<list>
#include<vector>
#include<functional>
template<typename key_t,typename val_t,typename hash_t=std::hash<key_t>, typename keyeq_t = std::equal_to<key_t>>
class my_hash_map {
using pair_t = std::pair<const key_t, val_t>;
using container_t = std::list<std::pair<const key_t, val_t>>;
using iterator = typename container_t::iterator;
using const_iterator = typename container_t::const_iterator;
container_t elem_list;
vector<iterator> 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<decltype(*this)>::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<typename key_t, typename val_t,typename hash_t, typename keyeq_t>
const hash_t my_hash_map<key_t, val_t, hash_t, keyeq_t>::hash;
template<typename key_t, typename val_t, typename hash_t, typename keyeq_t>
const keyeq_t my_hash_map<key_t, val_t, hash_t, keyeq_t>::eq;
#endif //_MY_HASH_MAP_H_