数据结构(Java)-哈希表

哈希表

1. 基本概念

哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方,说起来可能感觉有点复杂,我想我举个例子你就会明白了,最典型的的例子就是字典,大家估计小学的时候也用过不少新华字典吧,如果我想要获取“按”字详细信息,我肯定会去根据拼音an去查找 拼音索引(当然也可以是偏旁索引),我们首先去查an在字典的位置,查了一下得到“安”,结果如下。这过程就是键码映射,在公式里面,就是通过key去查找f(key)。其中,按就是关键字(key),f()就是字典索引,也就是哈希函数,查到的页码4就是哈希值。
通过字典查询数据
核心:

  1. 内部是一个数组
  2. 关键字经过变换(hash函数)得到int类型的值
  3. int类型的值变成一个合法的下标
  4. 把关键字放到这个合法的下标位置

2. 冲突

对于不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突(哈希碰撞)。

3. 避免冲突

由于哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致了冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率

4. 冲突-避免-哈希函数的设计

哈希函数的设计:

  • 哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间
  • 哈希函数计算出来的地址能均匀分布在整个空间中
  • 哈希函数应该比较简单

4.1 常见的哈希函数

1. 直接定制法–(常用)
取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
优点: 简单、均匀
缺点: 需要事先知道关键字的分布情况
使用场景: 适合查找比较小且连续的情况

2. 除留余数法–(常用)
设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址

5. 冲突-避免-负载因子调节

  • 负载因子的定义为:填入表中的元素个数 / 散列表长度
  • 对于开方地址法,负载因子特别重要,要严格控制在0.7~0.8以下,一旦超过0.8哈希表的查找效率就非常低,所以在java的系统库限制了负载因子为0.75,超过或者达到就会resize(扩容)。
  • 已知哈希表中的关键字个数是不可变的,那我们就只有调整哈希表中的数组的大小。(扩容)

6. 解决冲突

常见的解决冲突的方式:闭散列和开散列

6.1 闭散列

闭散列:也叫开放地址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?

  • 线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。(再进行删除操作的时候易出错)
  • 二次探测 :从发生冲突的位置开始,依次向后探测,直到寻找到下(n^2)空位置为止。(再进行删除操作的时候易出错,而且空间利用低)

6.2 开散列(哈希桶)

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值