hash 的应用
散列表
根据key计算key在表中的位置的数据结构;是key和其所在存储地址的映射关系; 注意:散列表的节点中 kv是存储在一起的
struct node {
void *key;
void *val;
struct node *next;
}
与平衡二叉树相比
通过比较,结构有序,提升搜索效率
key与节点存储位置的映射关系
组成
hash函数
映射函数Hash(key)=addr,hash 函数可能会把两个或两个以上的不同key映射到同一地址,这种情况称之为冲突(或者hash碰撞);
数组
选择函数
- 计算速度快
- 强随机分布(等概率,均匀地分布在整个地址空间)
- murmurhash1,murmurhash2,murmurhash3,siphash(redis6.0当中使用,rust等大多数语言选用的hash算法来实现hashmap),cityhash都具备强随机分不行
- siphash主要解决字符串接近的强随机分布性 role:10001 role:10002
负载因子
数组存储元素的个数/数组长度;用来形容散列表的存储密度;负载因子越小,冲突越小,负载因子越大,冲突越大;需要注意扩容翻倍和缩容所导致的rehash
冲突处理
链表法
引用链表来处理哈希冲突,将冲突元素用链表链接起来,常用处理冲突的方式,但是如果冲突元素较多,该冲突链表过长,这个时候可以将这个链表转化成红黑树,最小堆;
由原来的时间复杂度O(n)转化为红黑树O(log2n),可以采用超过256个节点时候将链表结构转换为红黑树或堆结构。
开放寻址法
将所有元素都存放在哈希表的数组中,不使用额外的数据结构;一般使用线性探查的思路解决
- 当插入新元素的时候,使用哈希函数在哈希表中定位元素位置
- 检查数组中该槽位索引是否存在元素,如果为空就插入,否则转为3
- 在2检测的位置索引加上一定步长后在检查2;加一定的步长可以分为按 i+1,i+2...,i+n i+1^2,1+2^2,...,i+n^2 这两种都会导致同类的hash聚集,也就是近似值它的hash值也近似,形成hash聚集,第一种同类聚集冲突在前,第二种只是将聚集冲突延后;另外可以使用双重哈希解决
在stl 散列表中有 map,set,multimap,multiset 都是红黑树,unordered_map unordered_set unordered_multimap unordered_multiset 都是散列表
布隆过滤器
布隆过滤器通常用于判断某个key一定不存在的场景,同时允许判断存在时有误差的 布隆过滤器是一种概率型数据结构,高效地插入和查询,能确定某个字符串一定不存在和可能存在,另一方面布隆过滤器不存储具体数据,所以占用空间小,查询结果存在误差,但是误差可控,同时不支持删除操作。。
原理
当一个元素加入位图时,通过K个hash函数将这个元素映射到位图的K个点,并把他们位置为1,当检索时,再通过K个hash函数运算检测位图的k个点是否为1,如果有不为1的点,那么认为该key不存在,如果全部为1,则可能存在
为何不支持删除操作?
- 在位图中每个槽位只有两种状态(0或1),一个槽位被设置为1状态,但不确定它被设置了多少次,也就是不知道被多少个key哈希映射而来以及是被具体哪个hash函数映射而来。
- 不存在,只要一个索引位为0,如果都为1,不一定存在