【数据结构基础】【散列表】

散列表也叫做哈希表(hash table),这种数据结构提供了键(key)和值(value)的映射关系。只要给出一个key,就可以高效查找它匹配的value,时间复杂度接近O(1);

哈希函数

哈希函数通过某种方式,把key和数组下标进行转换。
在java中,每个对象都有属于自己的hashcode,这个hashcode是区分不同对象的重要标识。无论对象自身的类型是什么,他们的hashcode都是一个整型变量。
最简单的转化方式是按照数组长度进行取模运算:

index = HashCode(Key)%Array.length

JDK中的哈希函数并没有直接采取取模运算,而是利用位运算的方式来优化性能。
通过哈希函数,我们可以把字符串或其他类型的Key,转化成数组的下标index
例如长度为8的数组

key = 001121,
index = HashCode(“001121”)%Array.length=1420036703%8=7

散列表的读写扩容操作

1、写操作:在散列表中插入新的键值对
例如调用:

hashMap.put("002931","王五");

具体实现方式:
1、通过哈希函数,将key转换成数组下标,例如5
2、如果数组小标5对应的位置没有元素,就把这个键值对填充到数组下标为5的位置
但是,由于数组的长度是有限的,当插入的键值对越来越多,不同的key通过哈希函数获得的下标可能是相同的
这种情况叫做哈希冲突
例如:

002936的对应数组下标为2,;
002947的对应数组下标也是2;

哈希冲突是无法避免的。解决哈希冲突的方法:
1、开放寻址法
例如:第6组键值对通过哈希函数得到下标2,该下标在数组中已经有了其他元素,那么就向后移动1位,观察数组下标3是否有空
如果下标3也被占用,那么就再向后移动,直到找到空的位置。
(寻址的方式有很多,并不一定只是简单地寻找当前元素的后一个元素,这里只是简单举例)
2、链表法
HashMap数组的每个元素不仅是一个键值对对象,还是一个链表的头结点。每一个键值对对象通过next指针指向它的下一个键值对结点。当新来的键值对映射到与之冲突的数组位置时,只需要插入对应的链表中即可:
如下图:
在这里插入图片描述
2、读操作:通过给定的key,在散列表中查找对应的value
例如:调用函数hashMap.get(“002936”)
具体步骤:(以链表法为例)
1、通过哈希函数,将key转换成数组下标,例如2
2、找到数组下标2对应的元素,如果这个元素的key是002936,那么就找到了
如果这个key不是002936,由于数组的每个元素都与一个链表对应,我们可以顺着链表慢慢往下找,看看能否找到与key相匹配的结点

3、扩容操作:
当经过多次元素插入,散列表达到一定的饱和度时,key映射位置发生冲突的概率会逐渐提高。这样一来,大量元素拥挤在相同的数组下标位置形成很长的链表,对后续的插入和查询操作都会有很大影响。
此时就需要进行扩容:
影响扩容的因素:
1、HashMap当前长度
2、HashMap的负载因子,默认值为0.75f(在JDK中)
衡量HashMap需要进行扩容的操作如下:

HashMap.Size>=Capacity x LoadFactor

扩容具体步骤:
1、扩容,创建一个新的键值对空数组,长度是原数组的两倍
2、重新Hash,遍历原来的键值对数组,把所有的键值对重新Hash到新数组中(因为数组长度变化后,hash的规则也发生变化了)
经过扩容后,散列表重新变得稀疏。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拾牙慧者

欢迎请作者喝奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值