模仿stl,实现了开链法形式的hashtable。纯属练手,仅仅实现其基本功能,不当之处还望指正。本文为实现独立的空间配置器。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
template<class value>
struct _hash_node{
value val;
_hash_node *next;
~_hash_node(){delete val;}
};
template<class value,class key,class HashFcn,class EqualKey>
class _hashtable;
template<class T1,class T2>
class _hashfcn_mod;
template<class value,class key,class HashFcn,class EqualKey>
class _hashtable_iterator{
public:
typedef _hashtable<value,key,HashFcn,EqualKey> hashtable;
typedef _hashtable_iterator<value,key,HashFcn,EqualKey> iterator;
typedef _hash_node<value> node;
typedef forward_iterator_tag iterator_category;
typedef value value_type;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef value& reference;
typedef value* pointer;
node* cur;
hashtable* ht;
iterator(node* n,hashtable* tab):cur(n),ht(tab){}
iterator(){}
reference operator*()const{return cur->val;}
pointer operator->()const{return &(operator*()); }
iterator& operator++(){
const node* old = cur;
cur = cur->next; //须要推断cur的next是否存在
if(!cur){ //若此bucket list已经遍历到null 则继续向下一个bucket移动
size_type bucket = ht->bkt_num(old->val);
while(!cur&& ++bucket < ht->buckets.size())
cur = ht->buckets[bucket];
}
return *this;
}
iterator operator++(int){
const iterator old = cur;
++*this;
return old;
}
bool operator==(const iterator& it)const{return cur == it.cur;}
bool operator!=(const iterator& it)const{return cur != it.cur;}
};
static const int _stl_num_primes = 28; //保存28个质数来设计表格大小
static const unsigned long _stl_prime_list[_stl_num_primes] = {
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, 3221225473ul, 4294967291ul
}; //获取大于等于n的第一个质数
inline unsigned long _stl_next_prime(unsigned long n){
const unsigned long* first = _stl_prime_list;
const unsigned long* last = _stl_prime_list + _stl_num_primes;
const unsigned long* pos = lower_bound(first,last,n);
return pos == last? *(last-1):*pos;
}
template<class value,class key,class HashFcn,class EqualKey>
class _hashtable{
public:
typedef HashFcn hasher;
typedef EqualKey key_equal;
typedef value value_type;
typedef key key_type;
typedef value_type& reference;
typedef size_t size_type;
typedef _hash_node<value> node;
typedef _hashtable_iterator<value,key,HashFcn,EqualKey> iterator;
vector<node*> buckets;
private:
hasher hash; //哈希映射函数
key_equal equals;
size_type num_elements;
private:
void initialize_buckets(size_type n){
const size_type n_buckets = next_size(n);
buckets.reserve(n_buckets);
buckets.insert(buckets.end(), n_buckets, (node*) 0);
num_elements = 0;
}
size_type next_size(size_type n)const{return _stl_next_prime(n);}
void copy_from(const _hashtable& ht) {
buckets.clear();
buckets.reserve(ht.buckets.size());
buckets.insert(buckets.end(), ht.buckets.size(), (node*) 0);
try {
for (size_type i = 0; i < ht.buckets.size(); ++i) {
if (const node* cur = ht.buckets[i]) {
node* copy = new_node(cur->val);
buckets[i] = copy; for (node* next = cur->next; next; cur = next, next = cur->next) {
copy->next = new_node(next->val);
copy = copy->next;
}
}
}
num_elements = ht.num_elements;
}
catch(...){
clear();
}
}
node* new_node(const value_type& obj)
{
node* n = allocate((node*)0);
n->next = 0;
try {
construct(&n->val, obj);
return n;
}
catch(...){
deallocate(n);
exit(1);
}
}
template<class T>
T* allocate(T* a,ptrdiff_t size=1){
set_new_handler(0);
T* tmp = (T*)(::operator new((size_t)(size*sizeof(T))));
if(tmp == 0){
cerr<<"out of memory."<<endl;
exit(1);
}
return tmp;
}
template<class T1,class T2>
void construct(T1* p,const T2& value){new (p)T1(value);}
template<class T>
void deallocate(T* buffer){::operator delete(buffer);}
void clear(){
for (size_type i = 0; i < buckets.size(); ++i) {
node* cur = buckets[i];
while (cur != 0) {
node* next = cur->next;
delete_node(cur);
cur = next;
}
buckets[i] = 0;
}
num_elements = 0;
}
void delete_node(node* n)
{
destroy(&n->val);
deallocate(n);
}
template <class T>
void destroy(T* pointer) {
pointer->~T();
}
size_type bkt_num_key(const key_type& key)
{
return bkt_num_key(key, buckets.size());
}
size_type bkt_num_key(const key_type& key, size_t n)
{
return hash(key,n);// % n;
}
iterator insert_equal_noresize(const value_type& obj){
size_type n = bkt_num(obj);
node* first = buckets[n];
for(node* cur=first;cur;cur=cur->next){
if(equals(get_key(cur->val),get_key(obj))){
node* tmp = new_node(obj);
tmp->next = cur->next;
cur->next = tmp;
++num_elements;
returniterator(tmp,this);
}
}
node* tmp = new_node(obj);
tmp->next = first;
buckets[n] = tmp;
return iterator(tmp,this);
}
pair<iterator, bool> insert_unique_noresize(const value_type& obj){
const size_type n = bkt_num(obj);
node* first = buckets[n]; for (node* cur = first; cur; cur = cur->next)
if (equals(get_key(cur->val), get_key(obj)))
return pair<iterator, bool>(iterator(cur, this), false); node* tmp = new_node(obj);
tmp->next = first;
buckets[n] = tmp;
++num_elements;
return pair<iterator, bool>(iterator(tmp, this), true);
}
value_type get_key(const value_type& obj){
ExtractKey<value_type> tmp;
return tmp(obj);
}
public:
size_type bucket_size(){return buckets.size();}
_hashtable(size_type n,const HashFcn& hf,const EqualKey& eql):hash(hf),equals(eql){
initialize_buckets(n);
}
_hashtable(const _hashtable& ht):hash(ht.hash),equals(ht.equals),num_elements(0){
copy_from(ht);
}
_hashtable(){clear();}
size_type bucket_count()const{return buckets.size();}
size_type max_bucket_count()const{return _stl_prime_list[_stl_num_primes - 1];}
size_type elems_in_bucket(size_type bucket)const{
size_type result = 0;
for(*node cur = buckets[bucket];cur;cur = cur->next)
result += 1;
return result;
}
size_type bkt_num(const value_type& obj)
{
return bkt_num_key(get_key(obj));
}
size_type bkt_num(const value_type& obj, size_t n) const
{
return bkt_num_key(get_key(obj), n);
}
void resize(size_type num_elements_hint){
_hashfcn_mod<value_type,value_type> hashfcn_mod;
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){
vector<node*> tmp(n,(node*)0);
try{
for(size_type bucket=0;bucket<old_n;++bucket){
node* first = buckets[bucket];
while(first){
size_type new_bucket = hashfcn_mod(first->val,n);
buckets[bucket] = first->next;
first->next = tmp[new_bucket];
tmp[new_bucket] = first;
first = buckets[bucket];
}
}
buckets.swap(tmp);
}
catch(...){
for(size_type bucket=0;bucket<tmp.size();++bucket){
while(tmp[bucket]){
node* next = tmp[bucket]->next;
delete_node(tmp[bucket]);
tmp[bucket] = next;
}
}
throw;
}
}
}
}
pair<iterator,bool> insert_unique(const value_type& obj){
resize(num_elements+1);
return insert_unique_noresize(obj);
}
iterator insert_equal(const value_type& obj)
{
resize(num_elements + 1);
return insert_equal_noresize(obj);
}
iterator begin()
{
for (size_type n = 0; n < buckets.size(); ++n)
if (buckets[n])
return iterator(buckets[n], this);
return end();
}
iterator end() { return iterator(0, this); }
size_type erase(const key_type& key)
{
const size_type n = bkt_num_key(key);
node* first = buckets[n];
size_type erased = 0;
if (first) {
node* cur = first;
node* next = cur->next;
while (next) {
if (equals(get_key(next->val), key)) {
cur->next = next->next;
delete_node(next);
next = cur->next;
++erased;
--num_elements;
}
else {
cur = next;
next = cur->next;
}
}
if (equals(get_key(first->val), key)) {
buckets[n] = first->next;
delete_node(first);
++erased;
--num_elements;
}
}
return erased;
}
void erase(const iterator& it)
{
if (node* const p = it.cur) {
const size_type n = bkt_num(p->val);
node* cur = buckets[n]; if (cur == p) {
buckets[n] = cur->next;
delete_node(cur);
--num_elements;
}
else {
node* next = cur->next;
while (next) {
if (next == p) {
cur->next = next->next;
delete_node(next);
--num_elements;
break;
}
else {
cur = next;
next = cur->next;
}
}
}
}
}
reference find_or_insert(const value_type& obj){
resize(num_elements + 1);
size_type n = bkt_num(obj);
node* first = buckets[n]; for (node* cur = first; cur; cur = cur->next)
if (equals(get_key(cur->val), get_key(obj)))
return cur->val; node* tmp = new_node(obj);
tmp->next = first;
buckets[n] = tmp;
++num_elements;
return tmp->val;
}
iterator find(const key_type& key){
size_type n = bkt_num_key(key);
node* first;
for ( first = buckets[n];first && !equals(get_key(first->val), key);
first = first->next);
return iterator(first, this);
}
void erase(iterator first, iterator last){
size_type f_bucket = first.cur ? bkt_num(first.cur->val) : buckets.size();
size_type l_bucket = last.cur ? bkt_num(last.cur->val) : buckets.size();
if (first.cur == last.cur)return;
else if (f_bucket == l_bucket)erase_bucket(f_bucket, first.cur, last.cur);
else {
erase_bucket(f_bucket, first.cur, 0);
for (size_type n = f_bucket + 1; n < l_bucket; ++n)
erase_bucket(n, 0);
if (l_bucket != buckets.size())
erase_bucket(l_bucket, last.cur);
}
}
};
/*****************************************************
此函数对象用于定义映射函数。依据自己的需求能够定义线性探測、
二次线性探測或者自己定义函数
***********************************************************/
template<class T1,class T2>
class _hashfcn_mod{ //简单取余映射
public:
T1 operator()(T1 value,T2 size){ //value为key值 size为bucket长度
return value % size;
}
}; /*************************************************************
推断键值是否相等的函数,可自己定义
*************************************************************/
template<class T>
class _key_equal{
public:
bool operator()(T t1,T t2){
return t1 == t2;
}
}; /************************************************************
从节点中取出键值的方法。可自己定义
***********************************************************/
template<class T>
class ExtractKey{ //从节点取出键值
public:
T operator()(const T& tmp){
identity<T> id;
return id(tmp);
}
}; void test1(){
_hashfcn_mod<int,int> hashfcn;
_key_equal<int> keyequal;
_hashtable<int,int,_hashfcn_mod<int,int>,_key_equal<int>> hashtab(20,hashfcn,keyequal);
hashtab.insert_unique(15);
hashtab.insert_unique(14);
hashtab.insert_unique(13);
hashtab.insert_unique(12);
_hashtable<int,int,_hashfcn_mod<int,int>,_key_equal<int>>::iterator iter;
for(iter = hashtab.begin();iter!= hashtab.end();++iter)
cout<<*iter<<" ";
cout<<endl;
hashtab.erase(12);
for(iter = hashtab.begin();iter!= hashtab.end();++iter)
cout<<*iter<<" ";
cout<<endl;
hashtab.erase(hashtab.find(13));
for(iter = hashtab.begin();iter!= hashtab.end();++iter)
cout<<*iter<<" ";
cout<<endl;
}
int main(){
test1();
}

最新文章

  1. MongoDB 初见指南
  2. JAVA NIO中的Channels和Buffers
  3. C#----XML操作小结
  4. 微信5.4你所不知道的事 X5浏览引擎提速50%-80%
  5. WPF 中Frame + Page 的使用
  6. printf详解
  7. 企业级分布式监控系统-Zabbix基础
  8. shell之for和if实现批量替换多目录下的文件
  9. sqlserver2016新功能
  10. boost中Function和Lambda的使用
  11. ECSHOP /mobile/admin/edit_languages.php
  12. Azure DevOps Server (TFS)中代码文件换行问题解决方案(Git)
  13. Windows下安装WebLogic
  14. 你应该学会使用的5个ruby方法
  15. lua:值得看的博客资源 ...
  16. 20155327 实验三 敏捷开发与XP实践
  17. LSTM长短期记忆网络
  18. THREADSPOOL
  19. ZOJ 2770 Burn the Linked Camp 差分约束
  20. POJ 2386 Lake Counting 搜索题解

热门文章

  1. web前端之html基础知识初级
  2. Windows下svn使用教程
  3. 8VC Venture Cup 2017 - Elimination Round - B
  4. Polish orthography
  5. spring cloud学习一--Eureka服务注册与发现
  6. ubuntu在线搭建ftp服务器
  7. [Luogu2170]选学霸
  8. Facebook被指控通过其应用程序进行监视用户照片
  9. centos 6.5 关闭图形界面
  10. HTTP请求流程基础知识