哈希(闭散列)开放定址法实现

之前一篇博文中提过如何用开链法实现哈希表

这里是链接

那么对于哈希表的实现,还有另外一种方法的实现,这就是哈希开放定址法来实现。该方法也是用来处理哈希冲突的。解决思想如下:

现有关键字17,60,29,38

如何确定地址??可以看见该表的长度为11,那么使用关键字取余该表的长度,得到的余数就是该关键字的地址,17则余6,60则余5,29则余7,那么38也余了5,但是5这个地址已经存在关键字了,所以采用一种线性探测的方法,向后寻找一个位置,可以看见6这个地址也已经有了关键字,那就继续向后寻找,直到找到第一个空的位置,存放即可。



线性探测的方法在某种程度上冲突的几率会加大,比如说当有数十个余数相同的关键字时,哈希表的冲突就会尤为的集中,那么还有二次探测的方法,如果当前的位置冲突,向后移动2的冲突次方,即如果第一次冲突就移动1的2次方,第二次再冲突,移动-1的2次方,在该例子中,38就被放到了4这个位子,因为第一次移动是冲突的,则第二次是移动-1次了,即向左移动一个

对于第二种方式对于冲突能够比较分散



///////////////////////////////////////////线性探测//////////////////////////////////////////////
namespace OPEN{

	template<class K>
	struct _HashFunc
	{
		size_t operator()(const K& key)
		{
			return key;
		}
	};
	struct _HashFuncString
	{
		static size_t BKDRHash(const char * str)
		{
			unsigned int seed = 131; // 31 131 1313 13131 131313
			unsigned int hash = 0;
			while (*str)
			{
				hash = hash * seed + (*str++);
			}
			return (hash & 0x7FFFFFFF);
		}

		size_t operator()(const string& key)
		{
			return BKDRHash(key.c_str());
		}
	};
	enum State
	{
		EMPTY ,
		EXIST ,
		DELETE,
	};
	template<class K, class V>
	struct HashNode
	{
		K _key;
		V _value;
		State _state;//每个位置存了个状态,如果是空就可以扔值进去

		HashNode()
			:_state(EMPTY)
		{}
	};
	template<class K, class V>
	class HashTable
	{
		typedef HashNode<K,V> Node;
	public:
		HashTable()
			:_size(0)
		{}
		
		bool Insert(const K& key, const V& value){
			CheckCapacity();
			if (Find(key))
			{
				return false;
			}
			size_t index =HashFunc(key);
			while (_tables[index]._state == EXIST)
			{
				++index;
				if (index == _tables.size())
				{
					index = 0;
				}
			}
			_tables[index]._key = key;
			_tables[index]._value = value;
			_tables[index]._state = EXIST;
			_size++;
			return true;
		}
		size_t HashFunc(const K& key)
		{
			return  key%_tables.size();
		}
		//表不能满,满了之后会死循环
		Node* Find(const K& key)
		{
			size_t index = HashFunc(key);
			while (_tables[index]._state != EMPTY)
			{
				if (_tables[index]._key == key)
				{
					if (_tables[index]._state == EXIST)
					{
						return &_tables[index];
					}
					else
					{
						return NULL;
					}
				}
				++index;
				if (_tables.size() == index)
					index = 0;
			}
			return NULL;
		}
		void CheckCapacity()
		{
			if (_tables.size()==0||_size*10 / _tables.size() > 7)
			{
				size_t newsize = _tables.size() * 2;
				if (newsize == 0)
				{
					newsize = 10;
				}
				HashTable<K, V> newht;
				newht._tables.resize(newsize);
				for (size_t i = 0; i < _tables.size(); ++i)
				{
					if (_tables[i]._state == EXIST)
					{
						newht.Insert(_tables[i]._key, _tables[i]._value);
					}
				}
				_tables.swap(newht._tables);
			}
		}
		bool Remove(const K& key)
		{
			HashNode* node = Find(key);
			if (node)
			{
				node->_state = DELETE;
				--_size;
				return true;
			}
			else
			{
				return false;
			}
		}
	private:
		vector<Node> _tables;
		size_t _size;//为什么要加这个size,hash表不是线性的,是映射进去的,这个size代表数据的多少

	};
	void test()
	{
		int a[] = { 89, 18,49,58,9,23,45,12,66,67,98};
		HashTable<int, int> ht;
		for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
		{
			ht.Insert(a[i], i);
		}
	}
}


/////////////////////////////////////二次线性探测///////////////////////////////////////////
namespace OPEN{
	enum State
	{
		EMPTY,
		EXIST,
		DELETE,
	};
	template<class K, class V>
	struct HashNode
	{
		K _key;
		V _value;
		State _state;//每个位置存了个状态,如果是空就可以扔值进去

		HashNode()
			:_state(EMPTY)
		{}
	};
	//除string外的类型
	template<class K>
	struct _HashFunc
	{
		size_t operator()(const K& key)
		{
			return key;
		}
	};
	struct _HashFuncString
	{
		static size_t BKDRHash(const char * str)
		{
			unsigned int seed = 131; // 31 131 1313 13131 131313
			unsigned int hash = 0;
			while (*str)
			{
				hash = hash * seed + (*str++);
			}
			return (hash & 0x7FFFFFFF);
		}
		size_t operator()(const string& key)
		{
			return BKDRHash(key.c_str());
		}
	};
	template<class K, class V, class __HashFunc = _HashFunc<K> >//针对string需要给一个其他的模板
	class HashTable
	{
		typedef HashNode<K, V> Node;
	public:
		HashTable()
			:_size(0)
		{}

		bool Insert(const K& key, const V& value){
			CheckCapacity();
			if (Find(key))
			{
				return false;
			}
			size_t i = 1;
			size_t index = HashFunc(key);
			while (_tables[index]._state == EXIST)
			{
				index += i*i;
				index %= _tables.size();
				++i;
				if (index == _tables.size())
				{
					index = 0;
				}
			}
			_tables[index]._key = key;
			_tables[index]._value = value;
			_tables[index]._state = EXIST;
			_size++;
			return true;
		}
		//string不支持
		size_t HashFunc(const K& key)
		{
			__HashFunc hf;//仿函数
			return  hf(key)%_tables.size();
		}
		//表不能满,满了之后会死循环
		Node* Find(const K& key)
		{
			size_t index = HashFunc(key);
			while (_tables[index]._state != EMPTY)
			{
				if (_tables[index]._key == key)
				{
					if (_tables[index]._state == EXIST)
					{
						return &_tables[index];
					}
					else
					{
						return NULL;
					}
				}
				++index;
				if (_tables.size() == index)
					index = 0;
			}
			return NULL;
		}
		void CheckCapacity()
		{
			if (_tables.size() == 0 || _size * 10 / _tables.size() > 7)
			{
				size_t newsize = _tables.size() * 2;
				if (newsize == 0)
				{
					newsize = 10;
				}
				HashTable<K, V,__HashFunc> newht;
				newht._tables.resize(newsize);
				for (size_t i = 0; i < _tables.size(); ++i)
				{
					if (_tables[i]._state == EXIST)
					{
						newht.Insert(_tables[i]._key, _tables[i]._value);
					}
				}
				_tables.swap(newht._tables);
			}
		}
		bool Remove(const K& key)
		{
			HashNode* node = Find(key);
			if (node)
			{
				node->_state = DELETE;
				--_size;
				return true;
			}
			else
			{
				return false;
			}
		}
	private:
		vector<Node> _tables;
		size_t _size;//为什么要加这个size,hash表不是线性的,是映射进去的,这个size代表数据的多少

	};
	/*void test()
	{
		int a[] = { 89, 18, 49, 58, 9};
		HashTable<int, int> ht;
		for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
		{
			ht.Insert(a[i], i);
		}
	}*/
	/*void test()
	{
		
		HashTable<string, string, _HashFuncString> dict;
		dict.Insert("insert", "插入");
	
	}*/
}



猜你喜欢

转载自blog.csdn.net/qq_36474990/article/details/80219140
今日推荐