• hashtable C++实现


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

  • 相关阅读:
    js--数组中的最值
    js--数组合并并且去重
    js---数组去重的方法总结???
    input 输入框又被输入法遮挡啦
    使用装饰者模式改善既有代码
    简易的 webpack + vue 完成本地化数据 mock
    vue 数据持久化(刷新保存数据)的探索
    JavaScript await 与 promise 的纠葛
    javascript 函数的暂停和恢复
    Symbol 小妙处
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10889291.html
  • Copyright © 2020-2023  润新知