快存快查,向哈希表致敬

哈希表

  • 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
  • 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
  • 以上选自百度百科-散列表

哈希函数 address = H(key)

理想的哈希函数是指能将key尽可能均匀的散布到整个定长数组中。均匀的散布也就意味着极少的哈希冲突
哈希函数示例

构造方法说明适用场景
直接寻址法通过线性函数 H(key) = a*key + b 计算地址适用于需要散列的key之间也是线性关系的情况
除留余数法通过 H(key) = key % P (P <= 数组长度, 多数会取素数) 计算地址最简单,最常用的方法
随机数法通过 H(key) = random(key) 将key 作为随机数种子适用于key长度不等时。
平方取中法通过 key 的平方 然后取中间特定几位的方式 计算出散列地址 详情-Jeff_无法确定关键字中哪几位分布较均匀的时候
折叠法通过 将 key 分成长度相等的几部分,然后叠加舍去进位适用于关键字位数比较多,且关键字中每一位上数字分布大致均匀时
数字分析法出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址适用于哈希表中可能出现的关键字都是事先知道的并且数字之间满足进制关系
  • 散列: 将key通过哈希函数计算成地址的过程

哈希冲突和处理办法

哈希冲突

在使用哈希函数计算地址的时候,不可避免的会出现 key 不同但哈希后的地址一样的情况,这种情况就叫哈希冲突

处理办法
开放地址法

对于发成冲突的计算结果,将key加入特定的值后再进行哈希计算得到新的值,如新值未冲突就写,否则继续加入特定值计算哈希

链地址法

将发生冲突的key对应位置由存储为value进化为存储有一个个value的链表 此时对于此位置的查询由 O(1) 退化为 O(n) n为链表长度

公共溢出区

在声明哈希表的存储空间的时候,额外开辟一份空间用来存储冲突的地址

再哈希法

提前准备多个哈希函数,如果第一个冲突了,就用第二个依次类推

  • 在实际编程语言中,大多会采用链地址法处理哈希冲突,并且在链表过长的情况下将链表转为红黑树加速查询
  • 合理的哈希算法可以有效减少哈希冲突,比如Java通过位运算加快函数速度,额外的扰动函数提取更多key的特征来优化除留余数法
  • 合理的装载因子,装载因子 当前使用的位置/总可用位置 的值,如果值过大就会加大产生哈希冲突的概率

算法应用

  1. 简单 快乐数
  1. 中等 常数时间插入、删除和获取随机元素
  1. 布隆过滤器(Bloom Filter) 通过散列的形式快速判断 一个值是否在一个拥有海量值的集合中。

参考

  • java哈希表的细节实现 https://zhuanlan.zhihu.com/p/123261109
  • 这写的比我好多了 https://mp.weixin.qq.com/s/P0NUr86J3OCZFsn-aJAbtg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值