学习golang(3) 初探:编写一个链式hash map

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

我们昨天看了一下哈希表的几种常见的方式,以及如何解决hash冲突,最后我们看了一下go map的基本操作,今天我们来写一个demo,该demo是完成了一个简单的拉链式hash

什么是hash链式存储

哈希冲突

昨天已经讲过了该结构,我们再来看下,为什么有hash链式存储这个东西,其实hash本质是我们通过一个叫做哈希函数的东西来计算其存储点。

若多个key都被计算到同一个点,这个就称之为hash冲突

拉链式解决hash冲突

我们解决hash冲突的方法中,其中有一个就是拉链式存储。所谓拉链式存储,就是将数据使用链表给串起来。

这样在操作的时候,当定位到了下标后,就变为了链表的操作,这样,即解决了存储的问题,也解决了冲突的问题。

代码编写及逻辑

理想效果呈现

如上所述

我们可以将hash map其抽象为如下结构,该结构中,若遇到hash冲突,则将其值放入到链表中。

若我们将hash数组抽象一下,可能会得到如下效果

结构体定义

如上,我们将代码编写为 每一个hash map我们定义一个maps

maps又键值个数(count)、hash map数组长度 和 包含n个键值块(Node)

而每一个键值块(Node)又包含了一个键名(key)、一个键值(value) 以及 指向下一个键值块的指针(nextNode)

代码如下:

初始化hash map

初始化函数我们获取一个形参i,我们判断下i是否小于等于0,因为小于等于0,初始化无意义,所以我们判断若小于等于0,我们就默认给长度为10。

我们申请一个maps,并且将其count置为0,length为我们传入的值,然后再申请lengthNode指针,最后将maps给返回回去。

代码如下

定义哈希函数

hash存储中,最重要的就是hash函数,通过hash函数,我们就可以直接定位到存储点,hash函数设计得当与否直接影响到hash冲突的概率。

这里我们简单化了,若传入的keyint或则string时,我们计算其值,并且将对maps.length取余,其他类型直接存储数组0中,并且返回存储的下标。

新增数据

hash map中,key应当唯一才是,否则会影响hash map的正确性,所以在拿到要存储的keyvalue时,我们需要判断一下,如果该hash map中存在该值,则直接修改其值,或则是返回错误,这里定义为若key冲突,则为直接修改该值。

对于存储的逻辑,我们首先需要获取其数组存储的下标,在获取后,我们需要申请一个键值块(Node) ,然后将keyvalue赋值进该键值块中。

我们在进行存储的时候,相当于插入链表数据,而插入链表,我们又可以区分为3种情况

  • 该链表为空
  • 该链表只有一个节点
  • 该链表大于一个节点

当该链表为空时,我们直接将 键值块(Node) 放入数组中即可

原始链表

插入之后数据

当只有一个链表数据时,我们直接将 键值块(Node) 插入到第一个节点之后即可

原始链表

插入后链表

当链表超过2个节点时,我们将新节点插入第一个节点后,并且将新节点的下一个节点指向第一个节点的下一个节点

原始节点

插入后节点

我们整理为代码如下:

链表插入完毕后,我们使其count增加1

获取数据

其中对于获取数据,我们还是需要哈希函数key传入,获取其下标,然后就是对链表进行查询了

如果能够查询到该key,我们直接返回该键值块(Node)的地址,若查询不到,直接返回nil即可

删除数据

对于删除数据,和获取数据一样,我们需要找到数据,然后再进行链表的删除

对于找到数据,我们编写如下

若找到该数据,我们将其foundok赋值为true,并且定义currNodelastNode来获取当前节点指针和上一个节点指针

在找到数据后,我们又有三种删除逻辑

  • 尾节点
  • 头结点
  • 中间节点

当需要删除的节点是尾节点时

我们直接将上一个节点的指向赋值为nil即可

当需要删除的节点是头结点时

直接将数组赋值给头结点的下一个节点即可

当需要删除的节点是中间节点时

我们只需要将上一个节点的nextNode指针指向当前节点的下一个节点即可。

删除前

删除后

修改数据

修改数据如上新增数据逻辑

demo运行效果

我们编写主程序

编译测试

完美,赞

总结

hash表虽然很简单,但是用的非常多,其主要优点为,查询速度非常的块,哎,昨天看了一下go map底层实现,感觉非常复杂,我暂时还看不懂,所以先自己写了最简单的hash实现,争取我这个运维小学生有一天,能够看到go map实现代码吧。 哦,对了,上述代码我放在了giteegitee.com/pdudo/golea…

加油,加油。

posted @ 2022-04-23 18:09  pdudos  阅读(0)  评论(0编辑  收藏  举报  来源