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

hashtable C++实现

时间: 2024-08-30 04:44:55

hashtable C++实现的相关文章

HashMap和Hashtable

HashMap和Hashtable的区别 HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别.主要的区别有:线程安全性,同步(synchronization),以及速度. HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行). HashMap是非synchronized,而Hashtable

HashMap,Hashtable,ConcurrentHashMap 和 synchronized Map 的原理和区别

HashMap 是否是线程安全的,如何在线程安全的前提下使用 HashMap,其实也就是HashMap,Hashtable,ConcurrentHashMap 和 synchronized Map 的原理和区别.当时有些紧张只是简单说了下HashMap不是线程安全的:Hashtable 线程安全,但效率低,因为是 Hashtable 是使用 synchronized 的,所有线程竞争同一把锁:而 ConcurrentHashMap 不仅线程安全而且效率高,因为它包含一个 segment 数组,将

hashtable

HashTable是一种能提供快速插入和查询的数据结构,无论其包含有多少Item,查询和插入操作的平均时间总是接近O(1).hash function 的作用就是将这些范围很大的数(domain of keys )转换成我们需要的序号(domain of location)..net framework采用Division Methed作为其散列算法,使用取模(modulo)操作将Hash code值域转换到合适的范围.即:arrayIndex = hashcode % arraySize;其中

简易的hashtable实现

参考他人思路而写,具体可参考:http://blog.csdn.net/anialy/article/details/7620469 1 #ifndef _HASHTABLE_ 2 #define _HASHTABLE_ 3 #include<iostream> 4 using namespace std; 5 6 7 8 template<typename key_type,typename value_type> 9 struct HashNode{ 10 key_type k

JDK的弃儿:Vector、Stack、Hashtable、Enumeration

随着JDK的发展,一些设计缺陷或者性能不足的类库难免会被淘汰,最常见的就是Vector.Stack.HashTable和Enumeration了. Vector(@since 1.0) 首先看看Vector的UML类图,可以看出,他是一个与ArrayList有着相同继承体系的类,大致功能也和ArrayList一样.Vector与ArrayList最大的不同点在于它是线程安全的,因为其内部几乎所有方法都用了synchronized来修饰.但是,Synchronized是重量级锁,读写操作也没有做适

HashTable集合遍历的三种方法

hashtable集合遍历可以根据key,value以及key+value 示例代码: Hashtable table = new Hashtable(); Student stu = new Student(); stu.Name = "李四"; stu.Age = 18; Student stu1 = new Student(); stu1.Name = "张三"; stu1.Age = 18; Student stu2 = new Student(); stu

HashSet, HashTable

HashTable 存储键值对 , Hashtable和Dictionary<TKey,TValue>都是存键值对 HashSet 只存储值,盛放不同的数据,相同的数据只保留一份 HashSet<T>对集合运算的操作 public void IntersectWithTest() { HashSet<int> set1 = new HashSet<int>() { 1, 2, 3 }; HashSet<int> set2 = new HashSe

HashTable vs HashMap(三)

HashTable的应用非常广泛,HashMap是新框架中用来代替HashTable的类,也就是说建议使用HashMap,不要使用HashTable. 可能你觉得HashTable很好用,为什么不用呢?这里简单分析他们的区别. 1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样. 2.HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value

Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)

http://www.cnblogs.com/skywang12345/p/3311126.html 概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括:第1部分 Map概括第2部分 HashMap和Hashtable异同第3部分 HashMap和WeakHashMap异同 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311126 第1部分 Map概括 (01) Map

HashMap和Hashtable的区别

导读: 1 HashMap不是线程安全的 hastmap是一个接口 是map接口的子接口,是将键映射到值的对象,其中键和值都是对象,并且不能包含重复键,但可以包含重复值.HashMap允许null key和null value,而hashtable不允许. 2   HashTable是线程安全的一个Collection. HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可