模仿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();
}

hashtable C++实现的更多相关文章

  1. HashSet HashTable 与 TreeSet

    HashSet<T>类 HashSet<T>类主要是设计用来做高性能集运算的,例如对两个集合求交集.并集.差集等.集合中包含一组不重复出现且无特性顺序的元素. HashSet& ...

  2. Javascript实现HashTable类

    散列算法可以尽快在数据结构中找出指定的一个值,因为可以通过Hash算法求出值的所在位置,存储和插入的时候都按照Hash算法放到指定位置. <script> function HashTab ...

  3. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  4. java面试题——HashMap和Hashtable 的区别

    一.HashMap 和Hashtable 的区别 我们先看2个类的定义 public class Hashtable extends Dictionary implements Map, Clonea ...

  5. Map集合及与Collection的区别、HashMap和HashTable的区别、Collections、

    特点:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值. Map集合和Collection集合的区别 Map集合:成对出现 (情侣)                       ...

  6. HashTable初次体验

    用惯了数组.ArryList,初次接触到HashTable.Dictionary这种字典储存对于我来说简直就是高大上. 1.到底什么是HashTable HashTable就是哈希表,和数组一样,是一 ...

  7. HashMap和 Hashtable的比较

    Hashtable 和 HashMap的比较 1.  HashMap可以接受null(HashMap可以接受为null的键值(key)和值(value), HashTable不可以接受为null的键( ...

  8. hashMap和hashTable的区别

    每日总结,每天进步一点点 hashMap和hashTable的区别 1.父类:hashMap=>AbstractMap hashTable=>Dictionary 2.性能:hashMap ...

  9. SortedList和HashTable

    都是集合类,C#中同属命名空间System.Collections,“用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的 ...

  10. Java Hashtable的实现

    先附源码: package java.util; import java.io.*; /** * This class implements a hash table, which maps keys ...

随机推荐

  1. 道路识别demo

    最近做的道路识别一开始终于弄懂了点东西,一开始在网上找到了一个简单的道路识别的opencvsharp的版本.我觉得opencvsharp真的是一个很好的东西,它封装了比opencv更多的数据结构和库, ...

  2. 关于在IE下JavaScript的 Stack overflow at line 错误可能的原因

    该错误只在IE中出现,出现该提示的原因主要有两种: 1. 重定义了系统的触发事件名称作为自定义函数名如:  onclick / onsubmit …  都是系统保留的事件名称,不允许作为重定义函数名称 ...

  3. 2018-8-10-如何使用-Q#

    title author date CreateTime categories 如何使用 Q# lindexi 2018-08-10 19:16:51 +0800 2018-2-13 17:23:3 ...

  4. rabbitmq windows安装 及 centos安装

     windows安装如下: 安装方法如下网址: https://baijiahao.baidu.com/s?id=1605656085633071281&wfr=spider&for= ...

  5. https://blog.csdn.net/eguid_1/article/category/6270094

    https://blog.csdn.net/eguid_1/article/category/6270094

  6. 微信小程序(16)-- bindtap,catchtap事件绑定的区别

    bindtap,catchtap事件绑定的区别,这里就涉及冒泡事件了.bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡. logs.wxml <view cl ...

  7. bzoj4036 [HAOI2015]按位或 状压DP + MinMax 容斥

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4036 题解 变成 \(2^n-1\) 的意思显然就是每一个数位都出现了. 那么通过 MinMa ...

  8. apache You don't have permission to access / on this server.无权访问

    环境:ubuntu16.4 apache2 原因:修改了apache web项目路径 解决: 1. 修改 /etc/apache2/sites-available/000-default.conf 文 ...

  9. 【RabbitMQ】Concurrency、Prefetch、exclusive

    分布式消息中间件 RabbitMQ是用Erlang语言编写的分布式消息中间件,常常用在大型网站中作为消息队列来使用,主要目的是各个子系统之间的解耦和异步处理.消息中间件的基本模型是典型的生产者-消费者 ...

  10. Flutter 中的基本路由

    Flutter 中的路由通俗的讲就是页面跳转.在 Flutter 中通过 Navigator 组件管理路由导航,并提供了管理堆栈的方法.如:Navigator.push 和 Navigator.pop ...