哈希表实现及解决冲突的方法
哈希表,哈希冲突2016-11-04
#pragma once
#include<vector>
using namespace std;
#include<cmath>
#include<cstring>
namespace HASHTABLE
{
	enum Status{ EMPTY, DELETE, EXIST, };
	template<typename K, typename V>
	struct HashTableNode
	{
		K _key;
		V _value;
		Status _status;
		HashTableNode(const K& key = K(), const V& value = V())
			:_key(key)
			, _value(value)
			, _status(EMPTY)
		{}
	};
	template<typename K>
	struct __HashFunc
	{
		size_t operator()(const K& key)
		{
			return key;
		}
	};
	template<>                      //由于string用的也比较多,所以将string实现成偏特化
	struct __HashFunc<string>
	{
		size_t operator()(const string& str)
		{
			size_t num = 0;
			int len =(int)str.size();
			int i = 0;
			while (len--)
			{
				num += str[i] * (int)pow(128.0, len);
				i++;
			}
			return num;
		}
	};
	//线性探测           //二次探测
	template<typename K, typename V,class HashFunc=__HashFunc<K>>
	class HashTable
	{
		typedef HashTableNode<K, V> Node;
	public:
		HashTable()
			:_size(0)
		{
			_table.resize(_GetPrime(0));
		}
		HashTable(const HashTable<K, V,HashFunc>& hash)
		{
			size_t newsize = hash._table.size();           //得到hash的大小
			_table.resize(newsize);                       //先扩容
			for (size_t i = 0; i <_table.size(); i++)     //将hash表中的关键码拷贝到到新表中
			{
				if (hash._table[i]._status == EXIST)
				{
					_table[i]._key = hash._table[i]._key;
					_table[i]._value = hash._table[i]._value;
					_table[i]._status = EXIST;
				}
			}
			_size = hash._size;
		}
		HashTable<K, V, HashFunc>& operator=(const HashTable<K, V, HashFunc>& hash)
		{
			if (this != &hash)
			{
				HashTable<K, V, HashFunc> h(hash);
				Swap(h);
			}
			return *this;
		}
		Node* Find(const K& key)
		{
			int index = _HashFunc(key);
			if (index >= 0)
			{
				int start = index;        //记录第一次计算的位置
				while (_table[index]._status != EMPTY)      //这个位置要不为空
				{
					if (_table[index]._key == key)
					{
						//如果已经找到这个关键码,还要判断这个关键码的状态
						if (_table[index]._status == EXIST)
							return &_table[index];
					}
					index++;
					if (index == _table.size())
						index = 0;
					if (index == start)                    //如果此时表中都不为空,但是有标记删除的,所以还有可能再找到起始位置
						break;                             //这种情况是找不到的
				}
			}
			return NULL;
		}
		bool Insert(const K& key, const V& value)
		{
			_CheckCapacity();               //先判断需不需要增加表的长度
			int index = _HashFunc(key);
			if (index >= 0)         //如果已经找到了在hash中映射的地址
			{
				while (_table[index]._status == EXIST)  //先找到这个不为存在的位置,由于负载因子的存在,所以不可能全都是EXIST
				{
					index++;                        //线性探测可以改为二次探测,双散列也可以
					if (index == _table.size())
						index = 0;
				}
				//如果这个位置不是存在的状态,再插入
				_table[index]._key = key;
				_table[index]._value = value;
				_table[index]._status = EXIST;
				_size++;
				return true;
			}
			return false;
		}
		bool Remove(const K& key)
		{
			//要删除之前先要找到这个要删除的关键码
			Node* del = Find(key);
			if (del)                 //如果已经找到了要删除的关键码,则采用懒惰删除
			{
				del->_status = DELETE;
				_size--;                   //元素的个数要减一
				return true;
			}
			return false;
		}
		void Swap(HashTable<K, V, HashFunc>& table)
		{
			if (this != &table)         //不是自己与自己交换
			{
				_table.swap(table._table);
				swap(_size, table._size);
			}
		}
	protected:
		int _HashFunc(const K& key)
		{
			if (_table.size())
			{   //生成一个匿名对象,调用仿函数
				return HashFunc()(key)%_table.size();
			}
			return -1;
		}
		static unsigned _GetPrime(const unsigned long size)
		{
			const int _PrimeSize = 28;
			static const unsigned long _PrimeList[_PrimeSize] =
			{
				53ul, 97ul, 193ul, 389ul, 769ul,
				1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
				49157ul, 98317ul, 196613ul, 393241ul,
				786433ul,
				1572869ul, 3145739ul, 6291469ul, 12582917ul,
				25165843ul,
				50331653ul, 100663319ul, 201326611ul, 402653189ul,
				805306457ul,
				1610612741ul, 3221225473ul, 4294967291ul
			};
			for (size_t i = 0; i <_PrimeSize; i++)     //返回一个比当前hash表大的素数
			{
				if (size < _PrimeList[i])
					return _PrimeList[i];
			}
			return _PrimeList[_PrimeSize - 1];   //否则返回最后一个值
		}
		void _CheckCapacity() //如果载荷因子大于0.8,则这时候插入的效率就很低,所以这时候就要增大表的大小
		{
			//载荷因子等于元素的个数除以表的长度
			if (_table.size() == 0 || _size * 10 / _table.size() >= 8)   //这时候插入的效率很低,就要增加hash表的长度
			{
				//由于hash表已经扩容,所以要重新计算表中元素的哈希地址
				HashTable<K, V, HashFunc> hash;           //先创建一个临时的表
				size_t newsize = _GetPrime(_table.size());
				hash._table.resize(newsize);
				for (size_t i = 0; i <_table.size(); i++)     //将旧的表中的关键码拷贝到hash中
				{
					if (_table[i]._status == EXIST)
					{
						hash.Insert(_table[i]._key, _table[i]._value);
					}
				}
				//交换两个hash表
				Swap(hash);
			}
		}
	private:
		vector<Node> _table;
		size_t _size;
	};
}
namespace HashTable_link
{
	template<typename K,typename V>
	struct HashTableNode
	{
		K _key;
		V _value;
		HashTableNode<K, V>* _next;
		HashTableNode(const K& key=K(),const V& value=V())
			:_key(key)
			, _value(value)
			, _next(NULL)
		{}
	};
	template<class K>             //为了将得到hash地址统一起来,使用仿函数,将整型的时候默认实现出来
	struct __HashFunc               //仿函数,将关键值转换成整型数值
	{
		size_t operator()(const K& key)
		{
			return key;
		}
	};
	//由于string也是常用的类型,所以对string进行偏特化
	template<>
	struct __HashFunc<string>
	{
		size_t operator()(const string& str)
		{
			size_t num = 0;
			for (int i = 0; i < (int)str.size(); i++)
			{
				num += num * 131 +str[i];
			}
			return num;
		}
	};
	template<typename K,typename V,class HashFunc=__HashFunc<K>>       //仿函数默认类型是K
	class HashTable
	{
		typedef HashTableNode<K, V> Node;
	public:
		HashTable()
			:_size(0)
		{
			_tables.resize(_GetPrime(0));
		}
		HashTable(const HashTable<K, V,HashFunc>& hash)
		{
			_tables.resize(hash._tables.size());
			for (int i = 0; i <(int)hash._tables.size(); i++)             //将当前表的内容导入到新表
			{
				Node* cur = hash._tables[i];
				while (cur)
				{
					Insert(cur->_key, cur->_value);
					cur = cur->_next;
				}
			}
		}
		HashTable<K, V, HashFunc>& operator=(const HashTable<K, V, HashFunc>& hash)
		{
			if (this != &hash)           //如果不是自赋值
			{
				HashTable<K, V, HashFunc> tmp(hash);
				Swap(tmp);
			}
			return *this;
		}
		~HashTable()
		{
			for (int i = 0; i <(int)_tables.size(); i++)             //将当前表的内容导入到新表
			{
				Node* cur =_tables[i];
				Node* del = NULL;
				while (cur)
				{
					del = cur;
					cur = cur->_next;
					delete del;
				}
			}
		}
		Node* Find(const K& key)
		{
			int index = _HashFunc(key);
			if (index >= 0)
			{
				Node* cur = _tables[index];
				while (cur)
				{
					if (cur->_key == key)
					{
						return cur;
					}
					cur = cur->_next;
				}
			}
			return NULL;
		}
		bool Insert(const K& key,const V& value)
		{
			_CheckSize();                      //先判断表的载荷因子是否已经达到1,达到1的话就扩容
			Node* ret = Find(key);
			if (ret== NULL)                  //如果要插入的key不存在的,则可以插入
			{
				int index = _HashFunc(key);
				Node* cur = new Node(key,value);
				cur->_next = _tables[index];
				_tables[index] = cur;
				_size++;
				return true;
			}
			return false;
		}
		bool Remove(const K& key)
		{
			int index = _HashFunc(key);
			if (index >= 0)
			{
				Node* prev = NULL;
				Node* cur = _tables[index];
				while (cur)
				{
					if (cur->_key ==key)
					{
						if (prev == NULL)
						{
							_tables[index] = cur->_next;         //删除第一个结点
						}
						else
						{
							prev->_next = cur->_next;
						}
						delete cur;
						_size--;
						return true;
					}
					prev = cur;
					cur = cur->_next;
				}
			}
			return false;
		}
		void Swap(HashTable<K, V, HashFunc>& hash)
		{
			_tables.swap(hash._tables);
			swap(_size,hash._size);
		}
	protected:
		static unsigned _GetPrime(const unsigned long size)
		{
			const int _PrimeSize = 28;
			static const unsigned long _PrimeList[_PrimeSize] =
			{
				53ul, 97ul, 193ul, 389ul, 769ul,
				1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
				49157ul, 98317ul, 196613ul, 393241ul,
				786433ul,
				1572869ul, 3145739ul, 6291469ul, 12582917ul,
				25165843ul,
				50331653ul, 100663319ul, 201326611ul, 402653189ul,
				805306457ul,
				1610612741ul, 3221225473ul, 4294967291ul
			};
			for (size_t i = 0; i <_PrimeSize; i++)     //返回一个比当前hash表大的素数
			{
				if (size < _PrimeList[i])
					return _PrimeList[i];
			}
			return _PrimeList[_PrimeSize - 1];   //否则返回最后一个值
		}
		void _CheckSize()
		{
			if (_tables.size()==0||_size/_tables.size() == 1)       //如果表的长度为0,或者载荷因子为1,则先扩容
			{
				HashTable<K, V, HashFunc> hash;                            //创建一个临时的新hash表
				hash._tables.resize(_GetPrime(_tables.size()));
				for (int  i = 0; i <(int)_tables.size(); i++)             //将当前表的内容导入到新表
				{
					Node* cur = _tables[i];
					while (cur)
					{
						hash.Insert(cur->_key,cur->_value);
						cur = cur->_next;
					}
				}
				Swap(hash);            //交换两个表的内容
			}
		}
		int _HashFunc(const K& key)
		{
			if (_tables.size())
			{
				return (HashFunc()(key))%_tables.size();  //先构造一个匿名对象,再调用仿函数
			}
			return -1;
		}
	private:
		vector<Node*> _tables;
		size_t _size;
	};
}