从零开始写STL—哈希表
static const int _stl_num_primes = 28;
template<typename T, typename Hash = xhash<T>>
class hashtable;
ministl::vector<int> prime_list =
{
53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241,
786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611,
402653189, 805306457, 1610612741, 3221225473, 4294967291,
};
template<typename T>
class hash_iterator : public bidirectional_iterator<T>
{
public:
hashtable<T>* hash_ptr;
list_iterator<T> node_ptr;
list<T>* bucket_ptr;
hash_iterator(hashtable<T>* hp, list<T>* bp, list_iterator<T> np) :hash_ptr(hp), bucket_ptr(bp), node_ptr(np) {}
hash_iterator& operator++()
{
if (++node_ptr == bucket_ptr->end())
{
auto tmp = node_ptr;
--tmp;
size_t cur = hash_ptr->hash(*tmp, hash_ptr->bucket_size()) + 1;
while (cur < hash_ptr->bucket_size() && (*hash_ptr).data[cur].empty())
cur++;
bucket_ptr = cur < hash_ptr->bucket_size() ? &(hash_ptr->data[cur]) : hash_ptr->data.end();
node_ptr = (bucket_ptr == hash_ptr->data.end() ? nullptr : bucket_ptr->begin());
}
return *this;
}
hash_iterator operator++(int)
{
hash_iterator tmp = *this;
++*this;
return tmp;
}
hash_iterator& operator--()
{
if (node_ptr-- = bucket_ptr->begin())
{
size_t cur = hash_ptr->hash(*node_ptr, hash_ptr->bucket_size()) - 1;
if (cur < 0) cur = 0;
else
{
while (cur >= 0 && (*hash_ptr).data[cur].empty())
cur--;
}
bucket_ptr = &(hash_ptr->data[cur]);
node_ptr = bucket_ptr->begin();
}
return *this;
}
hash_iterator operator--(int)
{
hash_iterator tmp = *this;
--*this;
return tmp;
}
T& operator* ()
{
return *node_ptr;
}
bool operator==(const hash_iterator& rhs)
{
return hash_ptr == rhs.hash_ptr && node_ptr == rhs.node_ptr && bucket_ptr == rhs.bucket_ptr;
}
bool operator!=(const hash_iterator& rhs)
{
return !(*this == rhs);
}
};
template<typename T,typename Hash = xhash<T> >
class hashtable
{
friend class hash_iterator<T>;
public:
typedef T value_type;
typedef Hash hash_type;
typedef vector<list<T>> table;
typedef hash_iterator<T> iterator;
private:
Hash hash;
table data;
size_t elem_num;//the sum of all elements
pair<iterator, bool> _insert_unique_noresize(T val)
{
size_t index = hash(val, data.size());
for (auto it = data[index].begin(); it != data[index].end(); it++)
{
if (*it == val)
return make_pair<iterator, bool >(iterator(this, &data[index], it), false);
}
data[index].push_front(val);
elem_num++;
return make_pair<iterator, bool>(iterator(this, &data[index], data[index].begin()), true);
}
iterator _insert_equal_noresize(T val)
{
size_t index = hash(val, data.size());
for (auto it = data[index].begin(); it != data[index].end(); it++)
{
if (*it == val)
{
return iterator(this, &data[index], data[index].insert(it, val));
}
}
data[index].push_front(val);
elem_num++;
return iterator(this, &data[index], data[index].begin());
}
void initialize_buckets(size_t n)
{
data.resize(n);
elem_num = 0;
}
public:
hashtable()
{
initialize_buckets(53);
}
hashtable(size_t n)
{
initialize_buckets(next_prime(n));
}
void clear()
{
for (auto& it : data)
{
it.clear();
}
elem_num = 0;
}
bool empty()
{
return elem_num == 0;
}
pair<iterator, bool>find(const T& val)
{
size_t index = hash(val, data.size());
for (auto it = data[index].begin(); it != data[index].end(); it++)
{
if (*it == val)
return ministl::make_pair<iterator, bool >(iterator(this, &data[index], it), true);
}
return ministl::make_pair<iterator, bool >(end(), false);
}
iterator begin() const
{
auto it = data.begin();
while (it != data.end() && it->empty())
it++;
return iterator(const_cast<hashtable<T>*>(this), it, it == data.end() ? nullptr : it->begin());
}
iterator begin()
{
auto it = data.begin();
while (it != data.end() && it->empty())
it++;
return iterator(this, it, it == data.end() ? nullptr : it->begin());
}
iterator end() const
{
return iterator(const_cast<hashtable<T>*>(this), data.end(), nullptr);
}
iterator end()
{
return iterator(this, data.end(), nullptr);
}
inline unsigned long next_prime(unsigned long n)
{
for (auto it : prime_list)
{
if (it >= n)
return n;
}
return prime_list[_stl_num_primes - 1];
}
size_t bucket_size()
{
return data.size();
}
size_t bucket_size() const
{
return data.size();
}
size_t size()
{
return elem_num;
}
size_t hash_val(const T& val)
{
return hash(val, data.size());
}
pair<iterator, bool> insert_unique(T val)
{
rehash(elem_num + 1);
return _insert_unique_noresize(val);
}
iterator insert_equal(T val)
{
rehash(elem_num + 1);
return _insert_equal_noresize(val);
}
iterator erase_iter(iterator pos)
{
iterator ret = pos;
ret++;
pos.bucket_ptr->erase(pos.node_ptr);
return ret;
}
void erase_val(const T& val)
{
size_t index = hash(val, data.size());
for (auto it = data[index].begin(); it != data[index].end();)
{
if (*it == val)
it = data[index].erase(it);
else
it++;
}
}
void rehash(size_t n)
{
if (n > bucket_size())
{
elem_num = elem_num ? elem_num:1;
while (n > elem_num) elem_num *= 2;
size_t new_size = next_prime(elem_num);
hashtable new_table(new_size);
if (!empty())
{
iterator it = begin();
for (; it != end(); it++)
{
//std::cout << *it << std::endl;
new_table.insert_equal(*it);
}
}
swap(*this, new_table);
}
}
hashtable& operator=(const hashtable& rhs)
{
clear();
for (auto it = rhs.begin(); it != rhs.end(); it++)
{
insert_equal(*it);
}
return *this;
}
};
template<typename T>
void swap(const hashtable<T>& lhs, const hashtable<T>& rhs)
{
using ministl::swap;
swap(lhs.data, rhs.data);
swap(lhs.elem_num, rhs.elem_num);
swap(lhs.hash, rhs.hash);
}
template<typename T, typename Hash = xhash<T> >
class unordered_set
{
public:
typedef T value_type;
typedef Hash hash_type;
typedef vector<list<T>> table;
typedef hash_iterator<T> iterator;
typedef hashtable<T> seq;
private:
seq con;
public:
unordered_set() :con() {}
unordered_set(std::initializer_list<T> l)
{
unordered_set();
insert(l.begin(), l.end());
}
iterator begin()
{
return con.begin();
}
iterator end()
{
return con.end();
}
iterator find(const value_type& key)
{
return con.find(key).first;
}
iterator insert(const value_type& key)
{
return con.insert_unique(key).first;
}
iterator insert(value_type& key)
{
return con.insert_unique(key);
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
for (auto it = first; it != last; it++)
insert(*it);
}
size_t erase(const value_type& key)
{
size_t num = count(key);
if(num)
con.erase_val(key);
return num;
}
iterator erase(const iterator it)
{
return con.erase_iter(it);
}
iterator erase(const iterator first, const iterator last)
{
iterator it = first;
for (; it != last;)
it = con.erase_iter(it);
return it;
}
size_t count(const value_type& val)
{
return (con.find(val).second == true) ? 1 : 0;
}
bool empty()
{
return con.empty();
}
size_t size()
{
return con.size();
}
void clear()
{
con.clear();
}
void swap(unordered_set<T>& rhs)
{
using ministl::swap;
swap(con, rhs.con);
}
size_t bucket_count()
{
return con.bucket_size();
}
void rehash()
{
con.rehash(con.elem_num + 1);
}
double load_factor()
{
return 1.0 * con.elem_num / bucket_count();
}
};
//Todo: map_pair的hashval
//模板特化无法匹配?
template<typename K , typename T, typename Hash = xhash<map_pair<K,T>> >
class unordered_map
{
public:
typedef K key_type;
typedef T value_type;
typedef Hash hash_type;
typedef vector<list<map_pair<K,T>>> table;
typedef hash_iterator<map_pair<K,T>> iterator;
typedef hashtable<map_pair<K, T>, xhash<map_pair<K, T>> > seq;
private:
seq con;
public:
unordered_map() :con() {}
iterator begin()
{
return con.begin();
}
iterator begin() const
{
return con.begin();
}
iterator end()
{
return con.end();
}
iterator end() const
{
return con.end();
}
value_type& operator[](const key_type& key)
{
map_pair<K, T> p(key, T());
auto tmp = con.find(p);
iterator it = tmp.first;
if (tmp.second == false)
{
it = con.insert_equal(p);
}
return (*it).second;
}
value_type& at(const key_type& key)
{
auto tmp = con.find(key);
if (tmp.second == false)
{
std::cerr << "unordered_map out of range \n";
std::exit(1);
}
return (*it).second;
}
const value_type& at(const key_type& key) const
{
auto tmp = con.find(key);
if (tmp.second == false)
{
std::cerr << "unordered_map out of range \n";
std::exit(1);
}
return (*it).second;
}
iterator find(const key_type& key)
{
return con.find(key).first;
}
pair<iterator, iterator>
equal_range(const key_type& k)
{
auto first = con.find(k).first;
if (first == con.end())
return make_pair<iterator, iterator>(first, first);
else
{
iterator last = ++first;
while (last != con.end() && (*last == *first))
{
last++;
}
return make_pair<iterator, iterator>(first, last);
}
}
size_t count(const key_type& k)
{
auto first = con.find(k).first;
if (first == con.end())
return 0;
else
{
iterator last = ++first;
size_t cnt = 1;
while (last != con.end() && (*last == *first))
{
last++, cnt++;
}
return cnt;
}
}
auto insert(const map_pair<K, T> p)
{
return con.insert_unique(p);
}
size_t erase(const value_type& key)
{
size_t num = count(key);
if (num)
con.erase_val(key);
return num;
}
iterator erase(const iterator it)
{
return con.erase_iter(it);
}
iterator erase(const iterator first, const iterator last)
{
iterator it = first;
for (; it != last;)
it = con.erase_iter(it);
return it;
}
void rehash(size_t n)
{
con.rehash(n);
}
};
从零开始写STL—哈希表的更多相关文章
- 从零开始写STL - 智能指针
从零开始写STL - 智能指针 智能指针的分类及其特点: scoped_ptr:初始化获得资源控制权,在作用域结束释放资源 shared_ptr: 引用计数来控制共享资源,最后一个资源的引用被释放的时 ...
- 从零开始写STL—栈和队列
从零开始写STL-栈和队列 适配器模式 意图:将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 主要解决:主要解决在软件系统中,常常要将 ...
- 从零开始写STL—容器—vector
从0开始写STL-容器-vector vector又称为动态数组,那么动态体现在哪里?vector和一般的数组又有什么区别?vector中各个函数的实现原理是怎样的,我们怎样使用会更高效? 以上内容我 ...
- 从零开始写STL—模板元编程之any
any class any; (since C++17) The class any describes a type-safe container for single values of any ...
- 从零开始写STL—functional
function C++11 将任意类型的可调用(Callable)对象与函数调用的特征封装到一起. 这里的类是对函数策略的封装,将函数的性质抽象成组件,便于和algorithm库配合使用 基本运算符 ...
- 从零开始写STL—模板元编程之tuple
tuple Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generali ...
- 从零开始写STL—set/map
这一部分只要把搜索树中暴露的接口封装一下,做一些改动. set源码剖析 template<typename T> class set { public: typedef T key_typ ...
- [Codevs 1230]元素查找(手写哈希表)
题目连接:http://codevs.cn/problem/1230/ 说白了就是要我们自己手写一个哈希表的数据结构来实现加入和查找功能.map也能直接过(我第一次写就是用map骗AC的) 提一下个人 ...
- C++ STL中哈希表Map 与 hash_map 介绍
0 为什么需要hash_map 用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能.例如,我要记录一个人名和相应的存储,而且随时增加,要快速查找和修改: 岳不群-华 ...
随机推荐
- C# 调用第三方DLL缓冲区溢出导致的异常
这个倒是少见的错误,纪录一下大佬. 先上异常 错误一:尝试读取或写入受保护的内存 错误二:未将对象引用设置到对象的实例 错误三: 托管调试助手“FatalExecutionEngineError”( ...
- Eclipse--java.lang.OutOfMemoryError: PermGen space
这一段时间,Eclipse总是死掉,几乎是稍微操作快一点就会死掉,几分钟一次,搞得人郁闷至极.浪费了不少时间,在网上搜了下,看到很多朋友也出现类似的情况,在网上求救,但是网上的办法都只是说通过修改ec ...
- 【转】解决WPF图片模糊最佳方法(绑定PixelWidth与PixelHeight)
解决WPF图片模糊最佳方法(绑定PixelWidth与PixelHeight) 转载自:http://www.360doc.com/content/13/1126/09/10504424_332211 ...
- QT5:第二章 布局排版控件
一.简介 在QT组件面板中有Layouts和Spacers两个组件面板 注意:布局排版控件不显示 1.Layouts(布局) Vertical Layout:垂直方向布局,组件自动在垂直方向上分布 H ...
- linux(Ubuntu/Centos) iproute 路由IP地址等命令集合,查看端口链接
原 linux(Ubuntu/Centos) iproute 路由IP地址等命令集合,查看端口链接 2017年03月20日 16:55:57 风来了- 阅读数:2291 标签: centoslinux ...
- 微信小程序:errcode=40029和invalid code, hints: [ req_id: VyLhYa0451hb31 ]
问题: 后台用小程序返回的code请求微信服务器换取session_key和openid,返回错误状态码40029 解决问题 当前小程序绑定的appid和请求微信服务器所带的appid参数不一致导致的 ...
- Mac 安装Fiddler 抓包工具
官方安装文档https://www.telerik.com/download/fiddler/fiddler-osx-beta 如果输入mono Fiddler.exe报下面这个错误 WARNING: ...
- 乘法逆元-洛谷-P3811
题目背景 这是一道模板题 题目描述 给定n,p求1~n中所有整数在模p意义下的乘法逆元. 输入输出格式 输入格式: 一行n,p 输出格式: n行,第i行表示i在模p意义下的逆元. 输入输出样例 输入样 ...
- xmind 8 安装后启动失败(未提示错误信息)
xmind 8 安装后启动失败 前言 家里的计算机也安装了xmind,启动之后界面显示xmind的启动图标,几秒之后启动图标消失(闪退了),然后留我一脸懵逼.想着卸载了安装一个新的应该没有问题 ...
- 剑指Offer(书):数值的整数次方
题目:给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 分析: * 要注意以下几点:* 1.幂为负数时,base不能为0,不然求的时候是对 ...