中级C++:哈希

本文介绍了哈希的概念,包括哈希函数的构造方法和哈希冲突。讨论了闭散列(开放定址法)如线性探测和二次探测,以及开散列的实现,如哈希桶。文章还涵盖了插入、查找和删除操作,以及哈希表的负载因子。此外,提到了开散列在C++中作为`unordered_map`和`unordered_set`的实现。最后,作者鼓励编程学习者保持积极态度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

  • 以前的计数排序就是一种哈希结构,通过直接映射,或者间接映射;
  • 通过对pair<K,V>中的K进行取模、直接定制法(一元一次方程:Hash(Key)= A*Key + B))、平方取中法、数学分析法、 随机数法、折叠法等等一系列方法,把K映射到一个vector数组上。
  • 该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)。

哈希冲突

  • 发现不同的K值,取模后,可能会用同一个下标(哈希地址),该种现象称为哈希冲突或哈希碰撞。

哈希冲突的解决:闭散列,开散列。


闭散列

  • 也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。如果要查找某个元素,找到空也没有找到,说明不存在该元素。

空:用一个枚举类型,表示三种状态:存在、删除、空
在这里插入图片描述


线性探测

  • 线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
    • 如若走到头了,则和循环队列一样,%一个vector的长度可以回到下标 0 处。
    • 我的位置被占了,我就去占别人的位置。。
  • 负载因子:存放数据的个数,和数组的长度的比值;比值越低,说明冲突的可能性越小…应严格限制在0.7左右…

二次探测

  • 二次探测:找下一个空位置的方法进行了改进,让有相同哈希地址的分散一点,不要太集中。
  • 闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷。
  • ntspt = start+i*2;
namespace close_hash
{
   
    enum status
	{
   
		EMPTY,
		EXIST,
		DEL
	};
	template<class K,class V>
	struct hash_data
	{
   
		pair<K,V> _data;
		status _st = EMPTY;
	};
	---
	template<class K, class V>
	class hash_table
	{
   
		typedef hash_data<K, V> hashdata;
	public:
	....
	private:
		vector<hashdata> _ht;
		size_t  _n= 0;//有效数据的个数
	};
}

插入

       bool Insert(const pair<K, V>& kv)
		{
   
			if (find(kv.first))//先看K值在不在数组里
			{
   
				return false;
			}
			if (_n==_ht.size() || _n*10 /_ht.size()>=7)  //看是不是空的或者负载因子大于7 越大,说明越冲突
			{
   
				size_t newsize = _ht.size() == 0 ? 10 : _ht.size() * 2;
				hash_table<K,V> newht;
				newht._ht.resize(newsize);
				for (auto& i : _ht)
				{
   
					if (i._st == EXIST)//把是存在状态的数据插入到新数组里。
					{
   
						newht.Insert(i._data);
					}
				}
				_ht.swap(newht._ht);
			}
			size_t start = kv.first % _ht.size(); //数组的下标
			size_t i = 0;
			size_t inspt = start + i;//冲突了往后找空位置
			while (_ht[inspt]._st == EXIST)
			{
   
				++i;
				inspt = start + i;
				//intspt = start+i*2;
				inspt %= _ht.size();
			}
			_ht[inspt]._data = kv;
			_ht[inspt]._st = EXIST;
			_n++;
			return true;
		}

查找、删除

        hashdata* find(const K& key)
		{
   
			if (_n==0)
			{
   
				return nullptr;
			}
			size_t findk = key%_ht.size();//找坐标
			while (_ht[findk]._st != EMPTY)
			{
   
				if (_ht[findk]._st == EXIST && _ht[findk]._data.first == key
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值