哈希简单介绍,以及如何解决哈希冲突

关联式容器:map,set,mutil_map,mutil_set,unordered_map,unordered_set,

搜索

静态搜索
场景:一个序列的数据
顺序查找----for遍历----->o(n)
二分查找---->要求:带查找的数据必须是有序的—>o(logN).要求是数据必须是有序的

动态搜索
二叉搜索树—在插入删除之后会自动进行调整—>但是如果插入的元素接近有序的话那么就会形成单支树,所以平均时间复杂度就是1/2n,所以时间复杂度就是O(N)
AVL:二叉搜索树 + 平衡因子 ----->保证树的平衡性:保证任意节点左右子树的高度差不超过1
效率就是O(logN)

红黑树里面的查找

以上的查询方式共同点:必须进行元素的比较,才可以进行查询

哈希
在查找元素,能否可以不用进行比较
必须对元素的存储结构进行改造:如果能够通过某种方式,将元素与其存储结构之间建立一一对应的关系

存储:
对于需要存储的数据,首先使用哈希函数进行处理,处理之后的数值作为该数据的地址,存储起来。
哈希函数又叫做散列函数,存储数据的结构就叫做哈希表

查找:
1.通过哈希函数计算元素在表格中的位置
2.检测该位置的元素是否为待查找的元素

哈希思想的时间复杂度为O(1)

哈希冲突(哈希碰撞)
不同的元素,通过相同的哈希函数,计算出了相同的哈希地址

解决哈希冲突的常用办法

1.检查哈希函数的设计是否合理,可能哈希函数不合理,导致离散性不是很好,那么如何评判一个哈希函数是否好坏呢?
在这里插入图片描述
设计哈希函数都要考虑的因素
1.哈希函数作用,就是建立地址和存储元素之间的一一对应关系,所以哈希函数的值域必须在表格的范围之内
2.函数函数必须要保证所求数据的离散型
3.哈希函数要尽可能的简单

常见哈希函数
直接定地址法:根据元素分布情况设计关于key的线性的函数
HASHFun(X) = X;
除留余数法
假如你现在有1000个位置去存储数字,那么就可以用数据 % 1000来求哈希地址,最好是模上一个素数(因为模上素数,产生冲突的概率比较小)。

平方取中法:
在这里插入图片描述
折叠取中法,随机数法

但是单纯的从哈希函数的地方出发来解决哈希冲突,是没有办法来解决的,也就就是说,无论如何选择哈希函数,只是可以降低哈希冲突,但是并不会从根本上解决哈希冲突。

解决哈希冲突的方法:
1.闭散列
从发生哈希冲突的位置开始,找下一个空余的位置
线性探测:找下一个空位置的方式----->逐个挨着依次往后查找
问题:那该如何知道当前位置里面有没有元素呢?
答案:在定义表格的类型的时候,可以存在一个标记位,这个标记位来表示当前位置是否有元素。
实际在闭散列中,设计每一个位置的时候,给每一个位置三种标记位,删除,空,存在,三种状态,假如目前位置还没有插入过元素的话,那就是空,现在存在有效元素的话就是存在,要是当前位置原来存储过元素,现在删除了的话,就使用删除来标价当前位置,为啥要设计一个删除位置呢?而不是在元素删除之后,直接将位置设置为空呢?主要就是为了更方便后续元素的查找,假如将当前位置给成空的话,那么在查找元素的时候,在遇到空之后就会直接返回没找到,要是是使用删除来标记的话,那么在遇到当前位置之后就会继续往后查找。

关于线性探测什么时候进行扩容
哈希负载平衡因子:

哈希表中的元素个数 / 表格的容量,我们一般把平衡因子控制在0.7以内
如何扩容:搬到新空间之后,所有数据都需要重新计算地址。

线性探测解决哈希冲突优缺点:
优点:简单
缺陷:
空间利用率不高------》70,哈希本来本来就是空间换时间的一种做法,所以空间利用率不高是肯定的
容易造成数据的堆积,发生冲突之后元素容易连成一片

于是对线性探测进行改进------二次探测

因为在线性探测中,是从发生哈希冲突的位置开始往后依次查找的,所以一旦发生冲突之后,容易造成数据的堆积
解决办法就是,不要依次挨着往后找,于是就不会产生堆积,也就是二次探测

缺陷:当表格中空位置比较少的时候,找下一个位置的时候,可能需要探测许多次。影响哈希的性能。
在这里插入图片描述

如何把string类型的字符串转换为整型:
将string类型的首地址,看成是字符串转换成的整形数据

交换元素的两种方式:
在这里插入图片描述
第一种需要借助临时空间
在这里插入图片描述
的第二种,借助内置的swap函数的话直接是交换三个指针就就行了,多以比较快速。

2.开散列
开散列又叫链地址法,首先对关键码集合用散列函数进行计算散列地址,具有相同的地址的关键码,归于同意自己和,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头节点存储在哈希表中。

平时基本也是开散列用的比较多,闭散列基本不怎么用
在这里插入图片描述
散列表(哈希桶)的大概图解:
在这里插入图片描述
开散列何时扩容,如何扩容:

考虑上面的问题就要先考虑的是,什么情况下哈希桶的性能最佳?
每个桶中只有一个结点是最佳的,所以最佳的扩容时机就是,哈希桶(所有哈希桶)中所存的元素个数和桶的个数相等的时候,我们进行扩容

原因:找哈希桶的最佳状态----》每个桶中都存储一个元素
》》每个桶中都有一个元素,如果继续插入肯定会发生冲突
》》桶的利用率此时是最大的

开散列扩容的时候能否按照闭散列的方式进行扩容
扩容方式,使用闭散列中类似的方式扩容
在这里插入图片描述
可以但是不好,因为我们想的是在将旧的哈希表和新的哈希表在完成数据的重新计算之后,交换指针就可以了,最后除了作用于就会把新指针指向的旧的哈希表销毁掉,但是不好,因为在开散列中我们已经创建了一个个的结点,假如在扩容的时候又是进行元素的拷贝,最后又销毁,就会很浪费资源,所以将就哈希桶下的结点直接通过新哈希桶的哈希函数计算之后,直接挂载到新哈希桶下,才是最完美的解决方式。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值