• java源码系列:HashMap源码验证,自己手写一个HashMap之02-写put方法以及思路、哈希冲突等


    写put方法的思路

    那接下来呢,我们就来写这个put的方法,那这个put的方法我们应该怎么去写呢?

    1、首先第一步就把我们这个key呢,通过进行哈希,然后算出它的这个哈希code,

    2、然后通过这个哈希code去取模,算出它的这个 index的下标,

    3、然后通过这个下标呢,去找到这个数组所对应的这个对象,

    就当前这个下标的这个节点的这个对象,然后通过这个对象,判断当前这个对象是否为空,

    4、如果为空的话说明什么意思?如果为空的话,就说明不会出现冲突,可以直接赋值,进行存储,

    5、那如果不为空呢,说明出现冲突了,那这个时候呢,要用链表进行存储,然后返回这个值就可以了。

    整个的过程就是这样的一个过程。

    步骤1:定义 哈希算法 方法

    首先呢,定义一个哈希算法,然后这个哈希算法呢,它传入一个值是key,

    然后呢,它会返回一个index这个值,

    所以呢,我们接下来就写一下这个方法,那这个哈希算法怎么去实现呢?

    其实非常简单,也就是说现在在这里的话,就返回这个值,这个值应该怎么去算呢?

    其实就是拿到我们的这个index,这个值等于多少?

    等于咱们这个key.hashCode,然后去取模,我这里取模16,

    算出这个值,算出这个值它可能会出现负数,如果说我们出现负数的话,

    我们这里会有问题,因为我们数组呢,它是从零开始的,

    那如果说出现这个负数,那怎么去解决呢?

    对,判断一下,如果当前这个值大于等于零的话,那我们就直接返回它。

    如果它不等于零或小于零的话,那就让它负负得正,就取它的绝对值就可以了。

    当然java里面提供的函数,也是可以支持的。

    步骤2:判断是否有哈希冲突

    好,那么现在我们计算出的这个下标,然后我们放到这个数组里面去,

    然后它就会返回当前这个Entry对象,然后当前这个Entry对象。

    如果空对象等于咱们这个Entry对象的话,那就说明什么呢?说明没有出现冲突。

    我们上面的数据,存哪些值是没有冲突的?王五、陈二、李四,还有刘一

    那为什么存刘一,没有冲突呢?

    因为我们在插入存储刘一的时候,此时此刻它的下标位置是没有数据的,为空!

    它是第一个进来存储的,所以它是没有冲突的!

    那else的话就是咱们这个有冲突,那冲突的话无非就两个值,

    一个就是咱们这个monkey,还有一个就是咱们这个张三,就这两个值,

    步骤3:如果为空的话,赋值存储

    所以呢,我们现在接下来,在这里就知道啊,如果是没有冲突的话,

    非常好理解,就是赋值,就我们让这个table它的这个index呢,进行赋值,

    就是我们在这里呢,拿到这个新值,赋值给这个下标,就可以了。

    但是后面我们现在进入这里,那我们这个赋值这个内容写什么呢。内容写什么?

    我们来思考一下内容写什么?内容无非就是我们插入的这些值吧,

    那我们现在插入这些值的话,我们每一个下标返回的是一个Entry对象,

    那这个Entry对象要存这些值的话,那我就要在这个Entry对象里面进行定义吧。

    所以呢,我在这里来定义它们的key、value,以及对应他们的index这个值,

    还有它的这个next对吧。生成它的有参构造,把这四个值加进去,对不对?

    所以在 if(null == entry)的石化,我们主要干什么? 只要去new一个Entry对象,

    然后呢,把我们要传入的,比如像我们的key、value,

    以及它的这个哈希值(这里直接就取index的值即可),

    然后next为空,因为这里王五、陈二、李四、刘一,他们的next都为空,

    所以这里的赋值为空就可以了。

    步骤4:如果不为空,代表冲突了,链表存储

    好,else的话,那就存 monkey 和张三,那这个时候应该怎么办?

    那这个时候呢,我要把这个值赋值过来,但是呢,我们现在已出现冲突了,

    要去用链表的形式,那应该怎么办?

    我们现在知道出现这种情况要用链表,那链表无非就用next这个元素,对吧,

    因为这个next它就是一个指针,指针也就是链表,

    那这个next元素,应该写什么内容呢?

    我们来去思考一下,

    当我去插这个monkey的时候,我当前的头节点,是张三,而张三去插入的时候,头节点是刘一。

    也就是说我每一次插入的话,都是什么?

    都是我上一次插入的这个节点。

    所以,如上图,我现在这里要去插monkey,那我取出来,当前这个 next 是不是张三,那我把这个张三赋值给 next,那是不是就可以了。

    1、而我当前在这个地方取出的这个节点值,是不是我即将要插入的这个节点位置里面的值,

    那这个节点值,就是我即将插入之前的值。也就是 张三这个实体的值

    2、所以我直接把这个Entry对象赋值给 next,是不是就可以。

    对吧,就取出当前这个元素,我们把这个元素复制给它的指针。就可以实现,OK,

    就这么简单,所以在这里呢,我们就可以通过在这里, 就直接把这个元素什么进行返回。

    这里我们还要进行size++,因为我们的每增加一个元素,我们这个数组它要增加1,

    好,我们已经把put的方法写完了。

  • 相关阅读:
    基于 SpringBoot + MyBatis 的在线音乐播放器
    redisson解决redis服务器的主从一致性问题
    全球AI投资减少,生成式AI面临挑战;Command R + 成首个击败GPT-4的开源模型
    Linux中的库(静态库和动态库)详解
    JSP EL表达式的基本语法及运算符(超详细)
    ebpf 网络跟踪原理
    springboot-mybatisplus-redis二级缓存
    CSS伪元素详解以及伪元素与伪类的区别
    【Spring Cloud】安装 ElasticSearch、KIbana
    SpringCloud微服务实战——搭建企业级开发框架(三十八):搭建ELK日志采集与分析系统
  • 原文地址:https://blog.csdn.net/YuDBL/article/details/126106041