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

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

这里是链接

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

现有关键字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", "插入");
	
	}*/
}



散列开放定址法是一种解决哈希冲突的方法,它的时间复杂度和空间复杂度如下: 时间复杂度: - 最好情况下,哈希表中没有冲突,查找、插入和删除操作的时间复杂度都是O(1)。 - 最坏情况下,哈希表中所有的关键字都映射到了同一个地址上,查找、插入和删除操作的时间复杂度都是O(n)。 - 平均情况下,查找、插入和删除操作的时间复杂度都是O(1)。 空间复杂度: - 散列开放定址法的空间复杂度取决于哈希表的大小和存储的元素个数,即O(m+n),其中m为哈希表的大小,n为存储的元素个数。 下面是一个使用散列开放定址法解决哈希冲突的Python代码示例: ```python class HashTable: def __init__(self, size): self.size = size self.keys = [None] * self.size self.values = [None] * self.size def put(self, key, value): hash_value = self.hash_function(key) if self.keys[hash_value] is None: self.keys[hash_value] = key self.values[hash_value] = value else: if self.keys[hash_value] == key: self.values[hash_value] = value else: next_slot = self.rehash(hash_value) while self.keys[next_slot] is not None and self.keys[next_slot] != key: next_slot = self.rehash(next_slot) if self.keys[next_slot] is None: self.keys[next_slot] = key self.values[next_slot] = value else: self.values[next_slot] = value def get(self, key): start_slot = self.hash_function(key) value = None stop = False found = False position = start_slot while self.keys[position] is not None and not found and not stop: if self.keys[position] == key: found = True value = self.values[position] else: position = self.rehash(position) if position == start_slot: stop = True return value def hash_function(self, key): return key % self.size def rehash(self, old_hash): return (old_hash + 1) % self.size ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值